parent
f330e5a73a
commit
8d7c83de66
@ -0,0 +1,47 @@ |
||||
Version 6.2.3 |
||||
- fixed InvalidOperationException when accessing Stream.ReadTimeout or Stream.WriteTimeout on CF |
||||
(bug #50321) |
||||
- fixed entity framework function processing so that it handles stored functions properly |
||||
(bug #45277) |
||||
- fixed a bug with prepared statements and unsigned bigint. Patch also provided a nice speedup to reading |
||||
integer values from the wire (bug #49794) |
||||
- fixed problem where not specifying the data type of the return value of a function caused it to |
||||
mistakenly use Decimal as the return type (bug #49642) |
||||
- fixed bug where a scipt that had an empty last line would cause an InvalidOperationException (bug #50344) |
||||
- fixed bug in logging that kept no index and bad index warnings from being sent |
||||
- fixed bug where giving a connection string option like (option=) and then trying to read |
||||
the option back via the property would fail (bug #51209) |
||||
- fixed bug where a connection could not be reused in the IDE in some circumstances (bug #41629) |
||||
- small performance fix (bug #51149) |
||||
- fixed issue with script execution & multi-char delimiters (bug #46429) |
||||
- fixed bug in table editor where clicking back on the last row added can sometimes |
||||
cause a ArgumentOutOfRange exception |
||||
- fixed bug where a commands batchable command text was not getting reset when the |
||||
command text was reset (bug #50444) |
||||
- fixed bug where using a currently non-batchable command in a batch would throw an exception |
||||
(bug #50123) |
||||
- fixed bug where binary or blob columns would prevent columns after that from appearing in the |
||||
query builder (bug #50171) |
||||
- ScriptCompleted event handler now uses EventArgs.Empty instead of null |
||||
- fixed parsing bug that was caused by special characters being jammed up beside a quoted identifier (bug #51610) |
||||
- added feature where sql queries that are longer than 300 chars are normalized and a new |
||||
query normalized log line is issues right after query opened to give the query normalized text |
||||
- fixed bug in sql generation when using a negated binary fragment in EF (bug #49850) |
||||
- fixed bug in tokenization where a nonterminated string in sql will cause a CLR exception |
||||
rather than throwing a syntax exception (bug #51788) |
||||
- added two requested features -- MySqlDataReader.GetFieldType(string columnname) & |
||||
MySqlDataReader.GetOrdinal() includes the name of the column in the exception when not found |
||||
(bug #47467) |
||||
|
||||
Version 6.2.2 |
||||
- Fix race condition during TransactionScope rollback (bug#35330) |
||||
- When sending file to server (LOAD DATA INFILE) open the file for read only, not for read/write |
||||
(bug #48944) |
||||
- Fixed precision calculation on decimal and newdecimal columns (bug #48171) |
||||
- Fixed problem caused by us not including a 'REFERENCED_TABLE_CATALOG' column in our |
||||
foreign keys collection (bug #48974) |
||||
|
||||
Version 6.2.1 |
||||
- fixed SessionProvider to be compatible with 4.x MySQL, replaced TIMESTAMPDIFF with TIME_TO_SEC |
||||
(bug#47219) |
||||
- implemented support for client SSL certificates |
@ -0,0 +1,343 @@ |
||||
GNU General Public License |
||||
************************** |
||||
|
||||
GNU GENERAL PUBLIC LICENSE |
||||
Version 2, June 1991 |
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. |
||||
675 Mass Ave, Cambridge, MA 02139, USA |
||||
Everyone is permitted to copy and distribute verbatim copies |
||||
of this license document, but changing it is not allowed. |
||||
|
||||
Preamble |
||||
|
||||
The licenses for most software are designed to take away your |
||||
freedom to share and change it. By contrast, the GNU General Public |
||||
License is intended to guarantee your freedom to share and change free |
||||
software--to make sure the software is free for all its users. This |
||||
General Public License applies to most of the Free Software |
||||
Foundation's software and to any other program whose authors commit to |
||||
using it. (Some other Free Software Foundation software is covered by |
||||
the GNU Library General Public License instead.) You can apply it to |
||||
your programs, too. |
||||
|
||||
When we speak of free software, we are referring to freedom, not |
||||
price. Our General Public Licenses are designed to make sure that you |
||||
have the freedom to distribute copies of free software (and charge for |
||||
this service if you wish), that you receive source code or can get it |
||||
if you want it, that you can change the software or use pieces of it |
||||
in new free programs; and that you know you can do these things. |
||||
|
||||
To protect your rights, we need to make restrictions that forbid |
||||
anyone to deny you these rights or to ask you to surrender the rights. |
||||
These restrictions translate to certain responsibilities for you if you |
||||
distribute copies of the software, or if you modify it. |
||||
|
||||
For example, if you distribute copies of such a program, whether |
||||
gratis or for a fee, you must give the recipients all the rights that |
||||
you have. You must make sure that they, too, receive or can get the |
||||
source code. And you must show them these terms so they know their |
||||
rights. |
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and |
||||
(2) offer you this license which gives you legal permission to copy, |
||||
distribute and/or modify the software. |
||||
|
||||
Also, for each author's protection and ours, we want to make certain |
||||
that everyone understands that there is no warranty for this free |
||||
software. If the software is modified by someone else and passed on, we |
||||
want its recipients to know that what they have is not the original, so |
||||
that any problems introduced by others will not reflect on the original |
||||
authors' reputations. |
||||
|
||||
Finally, any free program is threatened constantly by software |
||||
patents. We wish to avoid the danger that redistributors of a free |
||||
program will individually obtain patent licenses, in effect making the |
||||
program proprietary. To prevent this, we have made it clear that any |
||||
patent must be licensed for everyone's free use or not licensed at all. |
||||
|
||||
The precise terms and conditions for copying, distribution and |
||||
modification follow. |
||||
|
||||
GNU GENERAL PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. This License applies to any program or other work which contains |
||||
a notice placed by the copyright holder saying it may be distributed |
||||
under the terms of this General Public License. The "Program", below, |
||||
refers to any such program or work, and a "work based on the Program" |
||||
means either the Program or any derivative work under copyright law: |
||||
that is to say, a work containing the Program or a portion of it, |
||||
either verbatim or with modifications and/or translated into another |
||||
language. (Hereinafter, translation is included without limitation in |
||||
the term "modification".) Each licensee is addressed as "you". |
||||
|
||||
Activities other than copying, distribution and modification are not |
||||
covered by this License; they are outside its scope. The act of |
||||
running the Program is not restricted, and the output from the Program |
||||
is covered only if its contents constitute a work based on the |
||||
Program (independent of having been made by running the Program). |
||||
Whether that is true depends on what the Program does. |
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's |
||||
source code as you receive it, in any medium, provided that you |
||||
conspicuously and appropriately publish on each copy an appropriate |
||||
copyright notice and disclaimer of warranty; keep intact all the |
||||
notices that refer to this License and to the absence of any warranty; |
||||
and give any other recipients of the Program a copy of this License |
||||
along with the Program. |
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and |
||||
you may at your option offer warranty protection in exchange for a fee. |
||||
|
||||
2. You may modify your copy or copies of the Program or any portion |
||||
of it, thus forming a work based on the Program, and copy and |
||||
distribute such modifications or work under the terms of Section 1 |
||||
above, provided that you also meet all of these conditions: |
||||
|
||||
a) You must cause the modified files to carry prominent notices |
||||
stating that you changed the files and the date of any change. |
||||
|
||||
b) You must cause any work that you distribute or publish, that in |
||||
whole or in part contains or is derived from the Program or any |
||||
part thereof, to be licensed as a whole at no charge to all third |
||||
parties under the terms of this License. |
||||
|
||||
c) If the modified program normally reads commands interactively |
||||
when run, you must cause it, when started running for such |
||||
interactive use in the most ordinary way, to print or display an |
||||
announcement including an appropriate copyright notice and a |
||||
notice that there is no warranty (or else, saying that you provide |
||||
a warranty) and that users may redistribute the program under |
||||
these conditions, and telling the user how to view a copy of this |
||||
License. (Exception: if the Program itself is interactive but |
||||
does not normally print such an announcement, your work based on |
||||
the Program is not required to print an announcement.) |
||||
|
||||
These requirements apply to the modified work as a whole. If |
||||
identifiable sections of that work are not derived from the Program, |
||||
and can be reasonably considered independent and separate works in |
||||
themselves, then this License, and its terms, do not apply to those |
||||
sections when you distribute them as separate works. But when you |
||||
distribute the same sections as part of a whole which is a work based |
||||
on the Program, the distribution of the whole must be on the terms of |
||||
this License, whose permissions for other licensees extend to the |
||||
entire whole, and thus to each and every part regardless of who wrote it. |
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest |
||||
your rights to work written entirely by you; rather, the intent is to |
||||
exercise the right to control the distribution of derivative or |
||||
collective works based on the Program. |
||||
|
||||
In addition, mere aggregation of another work not based on the Program |
||||
with the Program (or with a work based on the Program) on a volume of |
||||
a storage or distribution medium does not bring the other work under |
||||
the scope of this License. |
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, |
||||
under Section 2) in object code or executable form under the terms of |
||||
Sections 1 and 2 above provided that you also do one of the following: |
||||
|
||||
a) Accompany it with the complete corresponding machine-readable |
||||
source code, which must be distributed under the terms of Sections |
||||
1 and 2 above on a medium customarily used for software interchange; or, |
||||
|
||||
b) Accompany it with a written offer, valid for at least three |
||||
years, to give any third party, for a charge no more than your |
||||
cost of physically performing source distribution, a complete |
||||
machine-readable copy of the corresponding source code, to be |
||||
distributed under the terms of Sections 1 and 2 above on a medium |
||||
customarily used for software interchange; or, |
||||
|
||||
c) Accompany it with the information you received as to the offer |
||||
to distribute corresponding source code. (This alternative is |
||||
allowed only for noncommercial distribution and only if you |
||||
received the program in object code or executable form with such |
||||
an offer, in accord with Subsection b above.) |
||||
|
||||
The source code for a work means the preferred form of the work for |
||||
making modifications to it. For an executable work, complete source |
||||
code means all the source code for all modules it contains, plus any |
||||
associated interface definition files, plus the scripts used to |
||||
control compilation and installation of the executable. However, as a |
||||
special exception, the source code distributed need not include |
||||
anything that is normally distributed (in either source or binary |
||||
form) with the major components (compiler, kernel, and so on) of the |
||||
operating system on which the executable runs, unless that component |
||||
itself accompanies the executable. |
||||
|
||||
If distribution of executable or object code is made by offering |
||||
access to copy from a designated place, then offering equivalent |
||||
access to copy the source code from the same place counts as |
||||
distribution of the source code, even though third parties are not |
||||
compelled to copy the source along with the object code. |
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program |
||||
except as expressly provided under this License. Any attempt |
||||
otherwise to copy, modify, sublicense or distribute the Program is |
||||
void, and will automatically terminate your rights under this License. |
||||
However, parties who have received copies, or rights, from you under |
||||
this License will not have their licenses terminated so long as such |
||||
parties remain in full compliance. |
||||
|
||||
5. You are not required to accept this License, since you have not |
||||
signed it. However, nothing else grants you permission to modify or |
||||
distribute the Program or its derivative works. These actions are |
||||
prohibited by law if you do not accept this License. Therefore, by |
||||
modifying or distributing the Program (or any work based on the |
||||
Program), you indicate your acceptance of this License to do so, and |
||||
all its terms and conditions for copying, distributing or modifying |
||||
the Program or works based on it. |
||||
|
||||
6. Each time you redistribute the Program (or any work based on the |
||||
Program), the recipient automatically receives a license from the |
||||
original licensor to copy, distribute or modify the Program subject to |
||||
these terms and conditions. You may not impose any further |
||||
restrictions on the recipients' exercise of the rights granted herein. |
||||
You are not responsible for enforcing compliance by third parties to |
||||
this License. |
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent |
||||
infringement or for any other reason (not limited to patent issues), |
||||
conditions are imposed on you (whether by court order, agreement or |
||||
otherwise) that contradict the conditions of this License, they do not |
||||
excuse you from the conditions of this License. If you cannot |
||||
distribute so as to satisfy simultaneously your obligations under this |
||||
License and any other pertinent obligations, then as a consequence you |
||||
may not distribute the Program at all. For example, if a patent |
||||
license would not permit royalty-free redistribution of the Program by |
||||
all those who receive copies directly or indirectly through you, then |
||||
the only way you could satisfy both it and this License would be to |
||||
refrain entirely from distribution of the Program. |
||||
|
||||
If any portion of this section is held invalid or unenforceable under |
||||
any particular circumstance, the balance of the section is intended to |
||||
apply and the section as a whole is intended to apply in other |
||||
circumstances. |
||||
|
||||
It is not the purpose of this section to induce you to infringe any |
||||
patents or other property right claims or to contest validity of any |
||||
such claims; this section has the sole purpose of protecting the |
||||
integrity of the free software distribution system, which is |
||||
implemented by public license practices. Many people have made |
||||
generous contributions to the wide range of software distributed |
||||
through that system in reliance on consistent application of that |
||||
system; it is up to the author/donor to decide if he or she is willing |
||||
to distribute software through any other system and a licensee cannot |
||||
impose that choice. |
||||
|
||||
This section is intended to make thoroughly clear what is believed to |
||||
be a consequence of the rest of this License. |
||||
|
||||
8. If the distribution and/or use of the Program is restricted in |
||||
certain countries either by patents or by copyrighted interfaces, the |
||||
original copyright holder who places the Program under this License |
||||
may add an explicit geographical distribution limitation excluding |
||||
those countries, so that distribution is permitted only in or among |
||||
countries not thus excluded. In such case, this License incorporates |
||||
the limitation as if written in the body of this License. |
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions |
||||
of the General Public License from time to time. Such new versions will |
||||
be similar in spirit to the present version, but may differ in detail to |
||||
address new problems or concerns. |
||||
|
||||
Each version is given a distinguishing version number. If the Program |
||||
specifies a version number of this License which applies to it and "any |
||||
later version", you have the option of following the terms and conditions |
||||
either of that version or of any later version published by the Free |
||||
Software Foundation. If the Program does not specify a version number of |
||||
this License, you may choose any version ever published by the Free Software |
||||
Foundation. |
||||
|
||||
10. If you wish to incorporate parts of the Program into other free |
||||
programs whose distribution conditions are different, write to the author |
||||
to ask for permission. For software which is copyrighted by the Free |
||||
Software Foundation, write to the Free Software Foundation; we sometimes |
||||
make exceptions for this. Our decision will be guided by the two goals |
||||
of preserving the free status of all derivatives of our free software and |
||||
of promoting the sharing and reuse of software generally. |
||||
|
||||
NO WARRANTY |
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED |
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS |
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE |
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, |
||||
REPAIR OR CORRECTION. |
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, |
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING |
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED |
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY |
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER |
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
||||
POSSIBILITY OF SUCH DAMAGES. |
||||
|
||||
END OF TERMS AND CONDITIONS |
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs |
||||
|
||||
If you develop a new program, and you want it to be of the greatest |
||||
possible use to the public, the best way to achieve this is to make it |
||||
free software which everyone can redistribute and change under these terms. |
||||
|
||||
To do so, attach the following notices to the program. It is safest |
||||
to attach them to the start of each source file to most effectively |
||||
convey the exclusion of warranty; and each file should have at least |
||||
the "copyright" line and a pointer to where the full notice is found. |
||||
|
||||
<one line to give the program's name and a brief idea of what it does.> |
||||
Copyright (C) 19yy <name of author> |
||||
|
||||
This program is free software; you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation; either version 2 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program; if not, write to the Free Software |
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
|
||||
Also add information on how to contact you by electronic and paper mail. |
||||
|
||||
If the program is interactive, make it output a short notice like this |
||||
when it starts in an interactive mode: |
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author |
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
||||
This is free software, and you are welcome to redistribute it |
||||
under certain conditions; type `show c' for details. |
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate |
||||
parts of the General Public License. Of course, the commands you use may |
||||
be called something other than `show w' and `show c'; they could even be |
||||
mouse-clicks or menu items--whatever suits your program. |
||||
|
||||
You should also get your employer (if you work as a programmer) or your |
||||
school, if any, to sign a "copyright disclaimer" for the program, if |
||||
necessary. Here is a sample; alter the names: |
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program |
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker. |
||||
|
||||
<signature of Ty Coon>, 1 April 1989 |
||||
Ty Coon, President of Vice |
||||
|
||||
This General Public License does not permit incorporating your program into |
||||
proprietary programs. If your program is a subroutine library, you may |
||||
consider it more useful to permit linking proprietary applications with the |
||||
library. If this is what you want to do, use the GNU Library General |
||||
Public License instead of this License. |
||||
|
@ -0,0 +1,119 @@ |
||||
MySQL FLOSS License Exception |
||||
|
||||
The MySQL AB Exception for Free/Libre and Open Source |
||||
Software-only Applications Using MySQL Client Libraries (the |
||||
"FLOSS Exception"). |
||||
|
||||
Version 0.6, 7 March 2007 |
||||
|
||||
Exception Intent |
||||
|
||||
We want specified Free/Libre and Open Source Software (``FLOSS'') |
||||
applications to be able to use specified GPL-licensed MySQL client |
||||
libraries (the ``Program'') despite the fact that not all FLOSS |
||||
licenses are compatible with version 2 of the GNU General Public |
||||
License (the ``GPL''). |
||||
|
||||
Legal Terms and Conditions |
||||
|
||||
As a special exception to the terms and conditions of version 2.0 |
||||
of the GPL: |
||||
|
||||
1. You are free to distribute a Derivative Work that is formed |
||||
entirely from the Program and one or more works (each, a |
||||
"FLOSS Work") licensed under one or more of the licenses |
||||
listed below in section 1, as long as: |
||||
a. You obey the GPL in all respects for the Program and the |
||||
Derivative Work, except for identifiable sections of the |
||||
Derivative Work which are not derived from the Program, |
||||
and which can reasonably be considered independent and |
||||
separate works in themselves, |
||||
b. all identifiable sections of the Derivative Work which |
||||
are not derived from the Program, and which can |
||||
reasonably be considered independent and separate works |
||||
in themselves, |
||||
i. are distributed subject to one of the FLOSS licenses |
||||
listed below, and |
||||
ii. the object code or executable form of those sections |
||||
are accompanied by the complete corresponding |
||||
machine-readable source code for those sections on |
||||
the same medium and under the same FLOSS license as |
||||
the corresponding object code or executable forms of |
||||
those sections, and |
||||
c. any works which are aggregated with the Program or with a |
||||
Derivative Work on a volume of a storage or distribution |
||||
medium in accordance with the GPL, can reasonably be |
||||
considered independent and separate works in themselves |
||||
which are not derivatives of either the Program, a |
||||
Derivative Work or a FLOSS Work. |
||||
If the above conditions are not met, then the Program may only |
||||
be copied, modified, distributed or used under the terms and |
||||
conditions of the GPL or another valid licensing option from |
||||
MySQL AB. |
||||
|
||||
2. FLOSS License List |
||||
|
||||
License name Version(s)/Copyright Date |
||||
Academic Free License 2.0 |
||||
Apache Software License 1.0/1.1/2.0 |
||||
Apple Public Source License 2.0 |
||||
Artistic license From Perl 5.8.0 |
||||
BSD license "July 22 1999" |
||||
Common Development and Distribution License (CDDL) 1.0 |
||||
Common Public License 1.0 |
||||
Eclipse Public License 1.0 |
||||
GNU Library or "Lesser" General Public License (LGPL) 2.0/2.1 |
||||
Jabber Open Source License 1.0 |
||||
MIT license (As listed in file MIT-License.txt) --- |
||||
Mozilla Public License (MPL) 1.0/1.1 |
||||
Open Software License 2.0 |
||||
OpenSSL license (with original SSLeay license) "2003" ("1998") |
||||
PHP License 3.0 |
||||
Python license (CNRI Python License) --- |
||||
Python Software Foundation License 2.1.1 |
||||
Sleepycat License "1999" |
||||
University of Illinois/NCSA Open Source License --- |
||||
W3C License "2001" |
||||
X11 License "2001" |
||||
Zlib/libpng License --- |
||||
Zope Public License 2.0 |
||||
|
||||
Due to the many variants of some of the above licenses, we |
||||
require that any version follow the 2003 version of the Free |
||||
Software Foundation's Free Software Definition |
||||
(http://www.gnu.org/philosophy/free-sw.html) or version 1.9 of |
||||
the Open Source Definition by the Open Source Initiative |
||||
(http://www.opensource.org/docs/definition.php). |
||||
|
||||
3. Definitions |
||||
|
||||
a. Terms used, but not defined, herein shall have the |
||||
meaning provided in the GPL. |
||||
b. Derivative Work means a derivative work under copyright |
||||
law. |
||||
|
||||
4. Applicability: This FLOSS Exception applies to all Programs |
||||
that contain a notice placed by MySQL AB saying that the |
||||
Program may be distributed under the terms of this FLOSS |
||||
Exception. If you create or distribute a work which is a |
||||
Derivative Work of both the Program and any other work |
||||
licensed under the GPL, then this FLOSS Exception is not |
||||
available for that work; thus, you must remove the FLOSS |
||||
Exception notice from that work and comply with the GPL in all |
||||
respects, including by retaining all GPL notices. You may |
||||
choose to redistribute a copy of the Program exclusively under |
||||
the terms of the GPL by removing the FLOSS Exception notice |
||||
from that copy of the Program, provided that the copy has |
||||
never been modified by you or any third party. |
||||
|
||||
Appendix A. Qualified Libraries and Packages |
||||
|
||||
The following is a non-exhaustive list of libraries and packages |
||||
which are covered by the FLOSS License Exception. Please note that |
||||
this appendix is provided merely as an additional service to |
||||
specific FLOSS projects wishing to simplify licensing information |
||||
for their users. Compliance with one of the licenses noted under |
||||
the "FLOSS license list" section remains a prerequisite. |
||||
|
||||
Package Name Qualifying License and Version |
||||
Apache Portable Runtime (APR) Apache Software License 2.0 |
@ -0,0 +1,3 @@ |
||||
This software product is not publicly available software. |
||||
This software product is MySQL commercial software and use of this |
||||
software is governed by your applicable license agreement with MySQL. |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,75 @@ |
||||
// Copyright (c) 2004-2007 MySQL AB |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Reflection; |
||||
using System.Runtime.InteropServices; |
||||
using System.Runtime.CompilerServices; |
||||
using System.Security; |
||||
|
||||
// |
||||
// General Information about an assembly is controlled through the following |
||||
// set of attributes. Change these attribute values to modify the information |
||||
// associated with an assembly. |
||||
// |
||||
[assembly: AssemblyDescription("ADO.Net driver for MySQL")] |
||||
[assembly: AssemblyConfiguration("")] |
||||
[assembly: AssemblyCompany("MySQL AB")] |
||||
[assembly: AssemblyProduct("")] |
||||
[assembly: AssemblyCopyright("Copyright 2004-2007, MySQL AB")] |
||||
[assembly: AssemblyTrademark("")] |
||||
[assembly: AssemblyCulture("")] |
||||
[assembly: ComVisible(false)] |
||||
[assembly: CLSCompliant(false)] |
||||
#if !CF |
||||
[assembly: AssemblyTitle("MySql.Data.dll")] |
||||
[assembly: AllowPartiallyTrustedCallers()] |
||||
#else |
||||
[assembly: AssemblyTitle("MySql.Data.CF.dll")] |
||||
#endif |
||||
|
||||
// |
||||
// In order to sign your assembly you must specify a key to use. Refer to the |
||||
// Microsoft .NET Framework documentation for more information on assembly signing. |
||||
// |
||||
// Use the attributes below to control which key is used for signing. |
||||
// |
||||
// Notes: |
||||
// (*) If no key is specified, the assembly is not signed. |
||||
// (*) KeyName refers to a key that has been installed in the Crypto Service |
||||
// Provider (CSP) on your machine. KeyFile refers to a file which contains |
||||
// a key. |
||||
// (*) If the KeyFile and the KeyName values are both specified, the |
||||
// following processing occurs: |
||||
// (1) If the KeyName can be found in the CSP, that key is used. |
||||
// (2) If the KeyName does not exist and the KeyFile does exist, the key |
||||
// in the KeyFile is installed into the CSP and used. |
||||
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. |
||||
// When specifying the KeyFile, the location of the KeyFile should be |
||||
// relative to the project output directory which is |
||||
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is |
||||
// located in the project directory, you would specify the AssemblyKeyFile |
||||
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] |
||||
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework |
||||
// documentation for more information on this. |
||||
// |
||||
//[assembly: AssemblyDelaySign(false)] |
||||
//[assembly: AssemblyKeyName("ConnectorNet")] |
||||
|
@ -0,0 +1,76 @@ |
||||
ACCESSIBLE ADD ALL |
||||
ALTER ANALYZE AND |
||||
AS ASC ASENSITIVE |
||||
BEFORE BETWEEN BIGINT |
||||
BINARY BLOB BOTH |
||||
BY CALL CASCADE |
||||
CASE CHANGE CHAR |
||||
CHARACTER CHECK COLLATE |
||||
COLUMN CONDITION CONNECTION |
||||
CONSTRAINT CONTINUE CONTRIBUTORS |
||||
CONVERT CREATE CROSS |
||||
CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP |
||||
CURRENT_USER CURSOR DATABASE |
||||
DATABASES DAY_HOUR DAY_MICROSECOND |
||||
DAY_MINUTE DAY_SECOND DEC |
||||
DECIMAL DECLARE DEFAULT |
||||
DELAYED DELETE DESC |
||||
DESCRIBE DETERMINISTIC DISTINCT |
||||
DISTINCTROW DIV DOUBLE |
||||
DROP DUAL EACH |
||||
ELSE ELSEIF ENCLOSED |
||||
ESCAPED EXISTS EXIT |
||||
EXPLAIN FALSE FETCH |
||||
FLOAT FLOAT4 FLOAT8 |
||||
FOR FORCE FOREIGN |
||||
FROM FULLTEXT GRANT |
||||
GROUP HAVING HIGH_PRIORITY |
||||
HOUR_MICROSECOND HOUR_MINUTE HOUR_SECOND |
||||
IF IGNORE IN |
||||
INDEX INFILE INNER |
||||
INOUT INSENSITIVE INSERT |
||||
INT INT1 INT2 |
||||
INT3 INT4 INT8 |
||||
INTEGER INTERVAL INTO |
||||
IS ITERATE JOIN |
||||
KEY KEYS KILL |
||||
LEADING LEAVE LEFT |
||||
LIKE LIMIT LINEAR |
||||
LINES LOAD LOCALTIME |
||||
LOCALTIMESTAMP LOCK LONG |
||||
LONGBLOB LONGTEXT LOOP |
||||
LOW_PRIORITY MATCH MEDIUMBLOB |
||||
MEDIUMINT MEDIUMTEXT MIDDLEINT |
||||
MINUTE_MICROSECOND MINUTE_SECOND MOD |
||||
MODIFIES NATURAL NOT |
||||
NO_WRITE_TO_BINLOG NULL NUMERIC |
||||
ON OPTIMIZE OPTION |
||||
OPTIONALLY OR ORDER |
||||
OUT OUTER OUTFILE |
||||
PRECISION PRIMARY PROCEDURE |
||||
PURGE RANGE READ |
||||
READS READ_ONLY READ_WRITE |
||||
REAL REFERENCES REGEXP |
||||
RELEASE RENAME REPEAT |
||||
REPLACE REQUIRE RESTRICT |
||||
RETURN REVOKE RIGHT |
||||
RLIKE SCHEMA SCHEMAS |
||||
SECOND_MICROSECOND SELECT SENSITIVE |
||||
SEPARATOR SET SHOW |
||||
SMALLINT SPATIAL SPECIFIC |
||||
SQL SQLEXCEPTION SQLSTATE |
||||
SQLWARNING SQL_BIG_RESULT SQL_CALC_FOUND_ROWS |
||||
SQL_SMALL_RESULT SSL STARTING |
||||
STRAIGHT_JOIN TABLE TERMINATED |
||||
THEN TINYBLOB TINYINT |
||||
TINYTEXT TO TRAILING |
||||
TRIGGER TRUE UNDO |
||||
UNION UNIQUE UNLOCK |
||||
UNSIGNED UPDATE UPGRADE |
||||
USAGE USE USING |
||||
UTC_DATE UTC_TIME UTC_TIMESTAMP |
||||
VALUES VARBINARY VARCHAR |
||||
VARCHARACTER VARYING WHEN |
||||
WHERE WHILE WITH |
||||
WRITE X509 XOR |
||||
YEAR_MONTH ZEROFILL |
1147
ThirdParty/mysql-connector-net-6.2.3/MySql.Data/Provider/Properties/Resources.Designer.cs
generated
vendored
1147
ThirdParty/mysql-connector-net-6.2.3/MySql.Data/Provider/Properties/Resources.Designer.cs
generated
vendored
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,460 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<root> |
||||
<!-- |
||||
Microsoft ResX Schema |
||||
|
||||
Version 2.0 |
||||
|
||||
The primary goals of this format is to allow a simple XML format |
||||
that is mostly human readable. The generation and parsing of the |
||||
various data types are done through the TypeConverter classes |
||||
associated with the data types. |
||||
|
||||
Example: |
||||
|
||||
... ado.net/XML headers & schema ... |
||||
<resheader name="resmimetype">text/microsoft-resx</resheader> |
||||
<resheader name="version">2.0</resheader> |
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> |
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> |
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> |
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> |
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> |
||||
<value>[base64 mime encoded serialized .NET Framework object]</value> |
||||
</data> |
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> |
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> |
||||
<comment>This is a comment</comment> |
||||
</data> |
||||
|
||||
There are any number of "resheader" rows that contain simple |
||||
name/value pairs. |
||||
|
||||
Each data row contains a name, and value. The row also contains a |
||||
type or mimetype. Type corresponds to a .NET class that support |
||||
text/value conversion through the TypeConverter architecture. |
||||
Classes that don't support this are serialized and stored with the |
||||
mimetype set. |
||||
|
||||
The mimetype is used for serialized objects, and tells the |
||||
ResXResourceReader how to depersist the object. This is currently not |
||||
extensible. For a given mimetype the value must be set accordingly: |
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format |
||||
that the ResXResourceWriter will generate, however the reader can |
||||
read any of the formats listed below. |
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64 |
||||
value : The object must be serialized with |
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter |
||||
: and then encoded with base64 encoding. |
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64 |
||||
value : The object must be serialized with |
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter |
||||
: and then encoded with base64 encoding. |
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64 |
||||
value : The object must be serialized into a byte array |
||||
: using a System.ComponentModel.TypeConverter |
||||
: and then encoded with base64 encoding. |
||||
--> |
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> |
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> |
||||
<xsd:element name="root" msdata:IsDataSet="true"> |
||||
<xsd:complexType> |
||||
<xsd:choice maxOccurs="unbounded"> |
||||
<xsd:element name="metadata"> |
||||
<xsd:complexType> |
||||
<xsd:sequence> |
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> |
||||
</xsd:sequence> |
||||
<xsd:attribute name="name" use="required" type="xsd:string" /> |
||||
<xsd:attribute name="type" type="xsd:string" /> |
||||
<xsd:attribute name="mimetype" type="xsd:string" /> |
||||
<xsd:attribute ref="xml:space" /> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
<xsd:element name="assembly"> |
||||
<xsd:complexType> |
||||
<xsd:attribute name="alias" type="xsd:string" /> |
||||
<xsd:attribute name="name" type="xsd:string" /> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
<xsd:element name="data"> |
||||
<xsd:complexType> |
||||
<xsd:sequence> |
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> |
||||
</xsd:sequence> |
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> |
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> |
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> |
||||
<xsd:attribute ref="xml:space" /> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
<xsd:element name="resheader"> |
||||
<xsd:complexType> |
||||
<xsd:sequence> |
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> |
||||
</xsd:sequence> |
||||
<xsd:attribute name="name" type="xsd:string" use="required" /> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
</xsd:choice> |
||||
</xsd:complexType> |
||||
</xsd:element> |
||||
</xsd:schema> |
||||
<resheader name="resmimetype"> |
||||
<value>text/microsoft-resx</value> |
||||
</resheader> |
||||
<resheader name="version"> |
||||
<value>2.0</value> |
||||
</resheader> |
||||
<resheader name="reader"> |
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
||||
</resheader> |
||||
<resheader name="writer"> |
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> |
||||
</resheader> |
||||
<data name="BadVersionFormat" xml:space="preserve"> |
||||
<value>Version string not in acceptable format</value> |
||||
</data> |
||||
<data name="NamedPipeNoSeek" xml:space="preserve"> |
||||
<value>NamedPipeStream does not support seeking</value> |
||||
</data> |
||||
<data name="StreamAlreadyClosed" xml:space="preserve"> |
||||
<value>The stream has already been closed</value> |
||||
</data> |
||||
<data name="BufferCannotBeNull" xml:space="preserve"> |
||||
<value> The buffer cannot be null</value> |
||||
</data> |
||||
<data name="BufferNotLargeEnough" xml:space="preserve"> |
||||
<value> Buffer is not large enough</value> |
||||
</data> |
||||
<data name="OffsetCannotBeNegative" xml:space="preserve"> |
||||
<value> Offset cannot be negative</value> |
||||
</data> |
||||
<data name="CountCannotBeNegative" xml:space="preserve"> |
||||
<value> Count cannot be negative</value> |
||||
</data> |
||||
<data name="StreamNoRead" xml:space="preserve"> |
||||
<value> The stream does not support reading</value> |
||||
</data> |
||||
<data name="NamedPipeNoSetLength" xml:space="preserve"> |
||||
<value>NamedPipeStream doesn't support SetLength</value> |
||||
</data> |
||||
<data name="StreamNoWrite" xml:space="preserve"> |
||||
<value>The stream does not support writing</value> |
||||
</data> |
||||
<data name="ErrorCreatingSocket" xml:space="preserve"> |
||||
<value>Error creating socket connection</value> |
||||
</data> |
||||
<data name="SocketNoSeek" xml:space="preserve"> |
||||
<value>Socket streams do not support seeking</value> |
||||
</data> |
||||
<data name="UnixSocketsNotSupported" xml:space="preserve"> |
||||
<value>Unix sockets are not supported on Windows</value> |
||||
</data> |
||||
<data name="OffsetMustBeValid" xml:space="preserve"> |
||||
<value>Offset must be a valid position in buffer</value> |
||||
</data> |
||||
<data name="CSNoSetLength" xml:space="preserve"> |
||||
<value>SetLength is not a valid operation on CompressedStream</value> |
||||
</data> |
||||
<data name="FromIndexMustBeValid" xml:space="preserve"> |
||||
<value>From index must be a valid index inside the from buffer</value> |
||||
</data> |
||||
<data name="FromAndLengthTooBig" xml:space="preserve"> |
||||
<value>From index and length use more bytes than from contains</value> |
||||
</data> |
||||
<data name="IndexMustBeValid" xml:space="preserve"> |
||||
<value>Index must be a valid position in the buffer</value> |
||||
</data> |
||||
<data name="IndexAndLengthTooBig" xml:space="preserve"> |
||||
<value>Index and length use more bytes than to has room for</value> |
||||
</data> |
||||
<data name="PasswordMustHaveLegalChars" xml:space="preserve"> |
||||
<value>Password must be valid and contain length characters</value> |
||||
</data> |
||||
<data name="ParameterCannotBeNegative" xml:space="preserve"> |
||||
<value>Parameter cannot have a negative value</value> |
||||
</data> |
||||
<data name="ConnectionMustBeOpen" xml:space="preserve"> |
||||
<value>Connection must be valid and open</value> |
||||
</data> |
||||
<data name="DataReaderOpen" xml:space="preserve"> |
||||
<value>There is already an open DataReader associated with this Connection which must be closed first.</value> |
||||
</data> |
||||
<data name="SPNotSupported" xml:space="preserve"> |
||||
<value>Stored procedures are not supported on this version of MySQL</value> |
||||
</data> |
||||
<data name="ConnectionNotSet" xml:space="preserve"> |
||||
<value>The connection property has not been set or is null.</value> |
||||
</data> |
||||
<data name="ConnectionNotOpen" xml:space="preserve"> |
||||
<value>The connection is not open.</value> |
||||
</data> |
||||
<data name="AdapterIsNull" xml:space="preserve"> |
||||
<value>Improper MySqlCommandBuilder state: adapter is null</value> |
||||
</data> |
||||
<data name="AdapterSelectIsNull" xml:space="preserve"> |
||||
<value>Improper MySqlCommandBuilder state: adapter's SelectCommand is null</value> |
||||
</data> |
||||
<data name="CBMultiTableNotSupported" xml:space="preserve"> |
||||
<value>MySqlCommandBuilder does not support multi-table statements</value> |
||||
</data> |
||||
<data name="CBNoKeyColumn" xml:space="preserve"> |
||||
<value>MySqlCommandBuilder cannot operate on tables with no unique or key columns</value> |
||||
</data> |
||||
<data name="ParameterCannotBeNull" xml:space="preserve"> |
||||
<value>Parameter cannot be null</value> |
||||
</data> |
||||
<data name="ChaosNotSupported" xml:space="preserve"> |
||||
<value>Chaos isolation level is not supported</value> |
||||
</data> |
||||
<data name="ParameterIsInvalid" xml:space="preserve"> |
||||
<value>Parameter is invalid.</value> |
||||
</data> |
||||
<data name="ConnectionAlreadyOpen" xml:space="preserve"> |
||||
<value>The connection is already open.</value> |
||||
</data> |
||||
<data name="KeywordNotSupported" xml:space="preserve"> |
||||
<value>Keyword not supported.</value> |
||||
</data> |
||||
<data name="WriteToStreamFailed" xml:space="preserve"> |
||||
<value>Writing to the stream failed.</value> |
||||
</data> |
||||
<data name="ReadFromStreamFailed" xml:space="preserve"> |
||||
<value>Reading from the stream has failed.</value> |
||||
</data> |
||||
<data name="QueryTooLarge" xml:space="preserve"> |
||||
<value>Packets larger than max_allowed_packet are not allowed.</value> |
||||
</data> |
||||
<data name="UnableToExecuteSP" xml:space="preserve"> |
||||
<value>Unable to execute stored procedure '{0}'.</value> |
||||
</data> |
||||
<data name="ProcAndFuncSameName" xml:space="preserve"> |
||||
<value>same name are not supported.</value> |
||||
</data> |
||||
<data name="KeywordNoNull" xml:space="preserve"> |
||||
<value>Keyword does not allow null values.</value> |
||||
</data> |
||||
<data name="ImproperValueFormat" xml:space="preserve"> |
||||
<value>Value has an unsupported format.</value> |
||||
</data> |
||||
<data name="InvalidProcName" xml:space="preserve"> |
||||
<value>Procedure or function '{0}' cannot be found in database '{1}'.</value> |
||||
</data> |
||||
<data name="HardProcQuery" xml:space="preserve"> |
||||
<value>Retrieving procedure metadata for {0} from server.</value> |
||||
</data> |
||||
<data name="SoftProcQuery" xml:space="preserve"> |
||||
<value>Retrieving procedure metadata for {0} from procedure cache.</value> |
||||
</data> |
||||
<data name="ConnectionBroken" xml:space="preserve"> |
||||
<value>Connection unexpectedly terminated.</value> |
||||
</data> |
||||
<data name="IncorrectTransmission" xml:space="preserve"> |
||||
<value>An incorrect response was received from the server.</value> |
||||
</data> |
||||
<data name="CancelNotSupported" xml:space="preserve"> |
||||
<value>Canceling an active query is only supported on MySQL 5.0.0 and above. </value> |
||||
</data> |
||||
<data name="Timeout" xml:space="preserve"> |
||||
<value>Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.</value> |
||||
</data> |
||||
<data name="CancelNeeds50" xml:space="preserve"> |
||||
<value>Canceling an executing query requires MySQL 5.0 or higher.</value> |
||||
</data> |
||||
<data name="NoNestedTransactions" xml:space="preserve"> |
||||
<value>Nested transactions are not supported.</value> |
||||
</data> |
||||
<data name="CommandTextNotInitialized" xml:space="preserve"> |
||||
<value>The CommandText property has not been properly initialized.</value> |
||||
</data> |
||||
<data name="UnableToParseFK" xml:space="preserve"> |
||||
<value>There was an error parsing the foreign key definition.</value> |
||||
</data> |
||||
<data name="PerfMonCategoryHelp" xml:space="preserve"> |
||||
<value>This category includes a series of counters for MySQL.</value> |
||||
</data> |
||||
<data name="PerfMonCategoryName" xml:space="preserve"> |
||||
<value>.NET Data Provider for MySQL</value> |
||||
</data> |
||||
<data name="PerfMonHardProcHelp" xml:space="preserve"> |
||||
<value>The number of times a procedures metadata had to be queried from the server.</value> |
||||
</data> |
||||
<data name="PerfMonHardProcName" xml:space="preserve"> |
||||
<value>Hard Procedure Queries</value> |
||||
</data> |
||||
<data name="PerfMonSoftProcHelp" xml:space="preserve"> |
||||
<value>The number of times a procedures metadata was retrieved from the client-side cache.</value> |
||||
</data> |
||||
<data name="PerfMonSoftProcName" xml:space="preserve"> |
||||
<value>Soft Procedure Queries</value> |
||||
</data> |
||||
<data name="WrongParameterName" xml:space="preserve"> |
||||
<value>Parameter '{0}' is not found but a parameter with the name '{1}' is found. Parameter names must include the leading parameter marker.</value> |
||||
</data> |
||||
<data name="UnableToConnectToHost" xml:space="preserve"> |
||||
<value>Unable to connect to any of the specified MySQL hosts.</value> |
||||
</data> |
||||
<data name="UnableToRetrieveSProcData" xml:space="preserve"> |
||||
<value>Unable to retrieve stored procedure metadata for routine '{0}'. Either grant SELECT privilege to mysql.proc for this user or use "use procedure bodies=false" with your connection string.</value> |
||||
</data> |
||||
<data name="NextResultIsClosed" xml:space="preserve"> |
||||
<value>Invalid attempt to call NextResult when the reader is closed.</value> |
||||
</data> |
||||
<data name="NoBodiesAndTypeNotSet" xml:space="preserve"> |
||||
<value>When calling stored procedures and 'Use Procedure Bodies' is false, all parameters must have their type explicitly set.</value> |
||||
</data> |
||||
<data name="TimeoutGettingConnection" xml:space="preserve"> |
||||
<value>error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.</value> |
||||
</data> |
||||
<data name="ParameterAlreadyDefined" xml:space="preserve"> |
||||
<value>Parameter '{0}' has already been defined.</value> |
||||
</data> |
||||
<data name="ParameterMustBeDefined" xml:space="preserve"> |
||||
<value>Parameter '{0}' must be defined.</value> |
||||
</data> |
||||
<data name="ObjectDisposed" xml:space="preserve"> |
||||
<value>The object is not open or has been disposed.</value> |
||||
</data> |
||||
<data name="MultipleConnectionsInTransactionNotSupported" xml:space="preserve"> |
||||
<value>Multiple simultaneous connections or connections with different connection strings inside the same transaction are not currently supported.</value> |
||||
</data> |
||||
<data name="DistributedTxnNotSupported" xml:space="preserve"> |
||||
<value>MySQL Connector/Net does not currently support distributed transactions.</value> |
||||
</data> |
||||
<data name="FatalErrorDuringExecute" xml:space="preserve"> |
||||
<value>Fatal error encountered during command execution.</value> |
||||
</data> |
||||
<data name="FatalErrorDuringRead" xml:space="preserve"> |
||||
<value>Fatal error encountered during data read.</value> |
||||
</data> |
||||
<data name="FatalErrorReadingResult" xml:space="preserve"> |
||||
<value>Fatal error encountered attempting to read the resultset.</value> |
||||
</data> |
||||
<data name="RoutineNotFound" xml:space="preserve"> |
||||
<value>Routine '{0}' cannot be found. Either check the spelling or make sure you have sufficient rights to execute the routine.</value> |
||||
</data> |
||||
<data name="ParameterNotFoundDuringPrepare" xml:space="preserve"> |
||||
<value>Parameter '{0}' was not found during prepare.</value> |
||||
</data> |
||||
<data name="ValueNotSupportedForGuid" xml:space="preserve"> |
||||
<value>The requested column value could not be treated as or conveted to a Guid.</value> |
||||
</data> |
||||
<data name="UnableToDeriveParameters" xml:space="preserve"> |
||||
<value>Unable to derive stored routine parameters. The 'Parameters' information schema table is not available and access to the stored procedure body has been disabled.</value> |
||||
</data> |
||||
<data name="UnableToRetrieveParameters" xml:space="preserve"> |
||||
<value>Unable to retrieve stored routine parameters. Either grant access to the routine or add the 'Use Procedure Bodies=false' option to your connection string.</value> |
||||
</data> |
||||
<data name="DefaultEncodingNotFound" xml:space="preserve"> |
||||
<value>The default connection encoding was not found. Please report this as a bug along with your connection string and system details.</value> |
||||
</data> |
||||
<data name="GetHostEntryFailed" xml:space="preserve"> |
||||
<value>Call to GetHostEntry failed after {0} while querying for hostname '{1}': SocketErrorCode={2}, ErrorCode={3}, NativeErrorCode={4}.</value> |
||||
</data> |
||||
<data name="UnableToEnumerateUDF" xml:space="preserve"> |
||||
<value>An error occured attempting to enumerate the user-defined functions. Do you have SELECT privileges on the mysql.func table?</value> |
||||
</data> |
||||
<data name="DataNotInSupportedFormat" xml:space="preserve"> |
||||
<value>The given value was not in a supported format.</value> |
||||
</data> |
||||
<data name="NoServerSSLSupport" xml:space="preserve"> |
||||
<value>The host {0} does not support SSL connections.</value> |
||||
</data> |
||||
<data name="CouldNotFindColumnName" xml:space="preserve"> |
||||
<value>Could not find specified column in results: {0}</value> |
||||
</data> |
||||
<data name="InvalidColumnOrdinal" xml:space="preserve"> |
||||
<value>You have specified an invalid column ordinal.</value> |
||||
</data> |
||||
<data name="ReadingPriorColumnUsingSeqAccess" xml:space="preserve"> |
||||
<value>Invalid attempt to read a prior column using SequentialAccess</value> |
||||
</data> |
||||
<data name="AttemptToAccessBeforeRead" xml:space="preserve"> |
||||
<value>Invalid attempt to access a field before calling Read()</value> |
||||
</data> |
||||
<data name="UnableToStartSecondAsyncOp" xml:space="preserve"> |
||||
<value>Unable to start a second async operation while one is running.</value> |
||||
</data> |
||||
<data name="MoreThanOneOPRow" xml:space="preserve"> |
||||
<value>INTERNAL ERROR: More than one output parameter row detected.</value> |
||||
</data> |
||||
<data name="InvalidValueForBoolean" xml:space="preserve"> |
||||
<value>'{0}' is an illegal value for a boolean option.</value> |
||||
</data> |
||||
<data name="ServerTooOld" xml:space="preserve"> |
||||
<value>Connector/Net no longer supports server versions prior to 4.1</value> |
||||
</data> |
||||
<data name="InvalidConnectionStringValue" xml:space="preserve"> |
||||
<value>The requested value '{0}' is invalid for the given keyword '{1}'.</value> |
||||
</data> |
||||
<data name="TraceCloseConnection" xml:space="preserve"> |
||||
<value>{0}: Connection Closed</value> |
||||
</data> |
||||
<data name="TraceOpenConnection" xml:space="preserve"> |
||||
<value>{0}: Connection Opened: connection string = '{1}'</value> |
||||
</data> |
||||
<data name="TraceQueryOpened" xml:space="preserve"> |
||||
<value>{0}: Query Opened: {2}</value> |
||||
</data> |
||||
<data name="TraceResult" xml:space="preserve"> |
||||
<value>{0}: Resultset Opened: field(s) = {1}, affected rows = {2}, inserted id = {3}</value> |
||||
</data> |
||||
<data name="TraceQueryDone" xml:space="preserve"> |
||||
<value>{0}: Query Closed</value> |
||||
</data> |
||||
<data name="TraceSetDatabase" xml:space="preserve"> |
||||
<value>{0}: Set Database: {1}</value> |
||||
</data> |
||||
<data name="TraceUAWarningBadIndex" xml:space="preserve"> |
||||
<value>{0}: Usage Advisor Warning: Query is using a bad index</value> |
||||
</data> |
||||
<data name="TraceUAWarningNoIndex" xml:space="preserve"> |
||||
<value>{0}: Usage Advisor Warning: Query does not use an index</value> |
||||
</data> |
||||
<data name="TraceResultClosed" xml:space="preserve"> |
||||
<value>{0}: Resultset Closed. Total rows={1}, skipped rows={2}, size (bytes)={3}</value> |
||||
</data> |
||||
<data name="TraceUAWarningSkippedRows" xml:space="preserve"> |
||||
<value>{0}: Usage Advisor Warning: Skipped {2} rows. Consider a more focused query.</value> |
||||
</data> |
||||
<data name="TraceUAWarningSkippedColumns" xml:space="preserve"> |
||||
<value>{0}: Usage Advisor Warning: The following columns were not accessed: {2}</value> |
||||
</data> |
||||
<data name="TraceUAWarningFieldConversion" xml:space="preserve"> |
||||
<value>{0}: Usage Advisor Warning: The field '{2}' was converted to the following types: {3}</value> |
||||
</data> |
||||
<data name="TraceOpenResultError" xml:space="preserve"> |
||||
<value>{0}: Error encountered attempting to open result: Number={1}, Message={2}</value> |
||||
</data> |
||||
<data name="TraceFetchError" xml:space="preserve"> |
||||
<value>{0}: Error encountered during row fetch. Number = {1}, Message={2}</value> |
||||
</data> |
||||
<data name="TraceWarning" xml:space="preserve"> |
||||
<value>{0}: MySql Warning: Level={1}, Code={2}, Message={3}</value> |
||||
</data> |
||||
<data name="TraceErrorMoreThanMaxValueConnections" xml:space="preserve"> |
||||
<value>Unable to trace. There are more than Int32.MaxValue connections in use.</value> |
||||
</data> |
||||
<data name="TraceStatementPrepared" xml:space="preserve"> |
||||
<value>{0}: Statement prepared: sql='{1}', statement id={2}</value> |
||||
</data> |
||||
<data name="TraceStatementClosed" xml:space="preserve"> |
||||
<value>{0}: Statement closed: statement id = {1}</value> |
||||
</data> |
||||
<data name="TraceStatementExecuted" xml:space="preserve"> |
||||
<value>{0}: Statement executed: statement id = {1}</value> |
||||
</data> |
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> |
||||
<data name="keywords" type="System.Resources.ResXFileRef, System.Windows.Forms"> |
||||
<value>keywords.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value> |
||||
</data> |
||||
<data name="TraceQueryNormalized" xml:space="preserve"> |
||||
<value>{0}: Query Normalized: {2}</value> |
||||
</data> |
||||
</root> |
@ -0,0 +1,39 @@ |
||||
// Copyright (C) 2004-2007 MySQL AB |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Reflection; |
||||
using System.Runtime.InteropServices; |
||||
using System.Runtime.CompilerServices; |
||||
using System.Security; |
||||
|
||||
// |
||||
// Version information for an assembly consists of the following four values: |
||||
// |
||||
// Major Version |
||||
// Minor Version |
||||
// Build Number |
||||
// Revision |
||||
// |
||||
// You can specify all the values or you can default the Revision and Build Numbers |
||||
// by using the '*' as shown below: |
||||
|
||||
[assembly: AssemblyVersion("6.2.3")] |
||||
|
@ -0,0 +1,229 @@ |
||||
ACCESSIBLE |
||||
ADD |
||||
ALL |
||||
ALTER |
||||
ANALYZE |
||||
AND |
||||
AS |
||||
ASC |
||||
ASENSITIVE |
||||
BEFORE |
||||
BETWEEN |
||||
BIGINT |
||||
BINARY |
||||
BLOB |
||||
BOTH |
||||
BY |
||||
CALL |
||||
CASCADE |
||||
CASE |
||||
CHANGE |
||||
CHAR |
||||
CHARACTER |
||||
CHECK |
||||
COLLATE |
||||
COLUMN |
||||
CONDITION |
||||
CONNECTION |
||||
CONSTRAINT |
||||
CONTINUE |
||||
CONVERT |
||||
CREATE |
||||
CROSS |
||||
CURRENT_DATE |
||||
CURRENT_TIME |
||||
CURRENT_TIMESTAMP |
||||
CURRENT_USER |
||||
CURSOR |
||||
DATABASE |
||||
DATABASES |
||||
DAY_HOUR |
||||
DAY_MICROSECOND |
||||
DAY_MINUTE |
||||
DAY_SECOND |
||||
DEC |
||||
DECIMAL |
||||
DECLARE |
||||
DEFAULT |
||||
DELAYED |
||||
DELETE |
||||
DESC |
||||
DESCRIBE |
||||
DETERMINISTIC |
||||
DISTINCT |
||||
DISTINCTROW |
||||
DIV |
||||
DOUBLE |
||||
DROP |
||||
DUAL |
||||
EACH |
||||
ELSE |
||||
ELSEIF |
||||
ENCLOSED |
||||
ESCAPED |
||||
EXISTS |
||||
EXIT |
||||
EXPLAIN |
||||
FALSE |
||||
FETCH |
||||
FLOAT |
||||
FLOAT4 |
||||
FLOAT8 |
||||
FOR |
||||
FORCE |
||||
FOREIGN |
||||
FROM |
||||
FULLTEXT |
||||
GOTO |
||||
GRANT |
||||
GROUP |
||||
HAVING |
||||
HIGH_PRIORITY |
||||
HOUR_MICROSECOND |
||||
HOUR_MINUTE |
||||
HOUR_SECOND |
||||
IF |
||||
IGNORE |
||||
IN |
||||
INDEX |
||||
INFILE |
||||
INNER |
||||
INOUT |
||||
INSENSITIVE |
||||
INSERT |
||||
INT |
||||
INT1 |
||||
INT2 |
||||
INT3 |
||||
INT4 |
||||
INT8 |
||||
INTEGER |
||||
INTERVAL |
||||
INTO |
||||
IS |
||||
ITERATE |
||||
JOIN |
||||
KEY |
||||
KEYS |
||||
KILL |
||||
LABEL |
||||
LEADING |
||||
LEAVE |
||||
LEFT |
||||
LIKE |
||||
LIMIT |
||||
LINEAR |
||||
LINES |
||||
LOAD |
||||
LOCALTIME |
||||
LOCALTIMESTAMP |
||||
LOCK |
||||
LONG |
||||
LONGBLOB |
||||
LONGTEXT |
||||
LOOP |
||||
LOW_PRIORITY |
||||
MASTER_SSL_VERIFY_SERVER_CERT |
||||
MATCH |
||||
MEDIUMBLOB |
||||
MEDIUMINT |
||||
MEDIUMTEXT |
||||
MIDDLEINT |
||||
MINUTE_MICROSECOND |
||||
MINUTE_SECOND |
||||
MOD |
||||
MODIFIES |
||||
NATURAL |
||||
NOT |
||||
NO_WRITE_TO_BINLOG |
||||
NULL |
||||
NUMERIC |
||||
ON |
||||
OPTIMIZE |
||||
OPTION |
||||
OPTIONALLY |
||||
OR |
||||
ORDER |
||||
OUT |
||||
OUTER |
||||
OUTFILE |
||||
PRECISION |
||||
PRIMARY |
||||
PROCEDURE |
||||
PURGE |
||||
RANGE |
||||
READ |
||||
READS |
||||
READ_ONLY |
||||
READ_WRITE |
||||
REAL |
||||
REFERENCES |
||||
REGEXP |
||||
RELEASE |
||||
RENAME |
||||
REPEAT |
||||
REPLACE |
||||
REQUIRE |
||||
RESTRICT |
||||
RETURN |
||||
REVOKE |
||||
RIGHT |
||||
RLIKE |
||||
SCHEMA |
||||
SCHEMAS |
||||
SECOND_MICROSECOND |
||||
SELECT |
||||
SENSITIVE |
||||
SEPARATOR |
||||
SET |
||||
SHOW |
||||
SMALLINT |
||||
SPATIAL |
||||
SPECIFIC |
||||
SQL |
||||
SQLEXCEPTION |
||||
SQLSTATE |
||||
SQLWARNING |
||||
SQL_BIG_RESULT |
||||
SQL_CALC_FOUND_ROWS |
||||
SQL_SMALL_RESULT |
||||
SSL |
||||
STARTING |
||||
STRAIGHT_JOIN |
||||
TABLE |
||||
TERMINATED |
||||
THEN |
||||
TINYBLOB |
||||
TINYINT |
||||
TINYTEXT |
||||
TO |
||||
TRAILING |
||||
TRIGGER |
||||
TRUE |
||||
UNDO |
||||
UNION |
||||
UNIQUE |
||||
UNLOCK |
||||
UNSIGNED |
||||
UPDATE |
||||
UPGRADE |
||||
USAGE |
||||
USE |
||||
USING |
||||
UTC_DATE |
||||
UTC_TIME |
||||
UTC_TIMESTAMP |
||||
VALUE |
||||
VALUES |
||||
VARBINARY |
||||
VARCHAR |
||||
VARCHARACTER |
||||
VARYING |
||||
WHEN |
||||
WHERE |
||||
WHILE |
||||
WITH |
||||
WRITE |
||||
XOR |
||||
YEAR_MONTH |
||||
ZEROFILL |
@ -0,0 +1,197 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using System.Collections.Generic; |
||||
using System.Data; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for CharSetMap. |
||||
/// </summary> |
||||
internal class CharSetMap |
||||
{ |
||||
private static Dictionary<string, string> defaultCollations; |
||||
private static Dictionary<string, int> maxLengths; |
||||
private static Dictionary<string, CharacterSet> mapping; |
||||
private static object lockObject; |
||||
|
||||
// we use a static constructor here since we only want to init |
||||
// the mapping once |
||||
static CharSetMap() |
||||
{ |
||||
lockObject = new Object(); |
||||
InitializeMapping(); |
||||
} |
||||
|
||||
public static CharacterSet GetCharacterSet(DBVersion version, string CharSetName) |
||||
{ |
||||
CharacterSet cs = (CharacterSet) mapping[CharSetName]; |
||||
if (cs == null) |
||||
throw new MySqlException("Character set '" + CharSetName + "' is not supported"); |
||||
return cs; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns the text encoding for a given MySQL character set name |
||||
/// </summary> |
||||
/// <param name="version">Version of the connection requesting the encoding</param> |
||||
/// <param name="CharSetName">Name of the character set to get the encoding for</param> |
||||
/// <returns>Encoding object for the given character set name</returns> |
||||
public static Encoding GetEncoding(DBVersion version, string CharSetName) |
||||
{ |
||||
try |
||||
{ |
||||
CharacterSet cs = GetCharacterSet(version, CharSetName); |
||||
return Encoding.GetEncoding(cs.name); |
||||
} |
||||
catch (NotSupportedException) |
||||
{ |
||||
return Encoding.GetEncoding(0); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// |
||||
/// </summary> |
||||
private static void InitializeMapping() |
||||
{ |
||||
LoadCharsetMap(); |
||||
} |
||||
|
||||
private static void LoadCharsetMap() |
||||
{ |
||||
mapping = new Dictionary<string, CharacterSet>(); |
||||
|
||||
mapping.Add("latin1", new CharacterSet("latin1", 1)); |
||||
mapping.Add("big5", new CharacterSet("big5", 2)); |
||||
mapping.Add("dec8", mapping["latin1"]); |
||||
mapping.Add("cp850", new CharacterSet("ibm850", 1)); |
||||
mapping.Add("hp8", mapping["latin1"]); |
||||
mapping.Add("koi8r", new CharacterSet("koi8-u", 1)); |
||||
mapping.Add("latin2", new CharacterSet("latin2", 1)); |
||||
mapping.Add("swe7", mapping["latin1"]); |
||||
mapping.Add("ujis", new CharacterSet("EUC-JP", 3)); |
||||
mapping.Add("eucjpms", mapping["ujis"]); |
||||
mapping.Add("sjis", new CharacterSet("sjis", 2)); |
||||
mapping.Add("cp932", mapping["sjis"]); |
||||
mapping.Add("hebrew", new CharacterSet("hebrew", 1)); |
||||
mapping.Add("tis620", new CharacterSet("windows-874", 1)); |
||||
mapping.Add("euckr", new CharacterSet("euc-kr", 2)); |
||||
mapping.Add("euc_kr", mapping["euckr"]); |
||||
mapping.Add("koi8u", new CharacterSet("koi8-u", 1)); |
||||
mapping.Add("koi8_ru", mapping["koi8u"]); |
||||
mapping.Add("gb2312", new CharacterSet("gb2312", 2)); |
||||
mapping.Add("gbk", mapping["gb2312"]); |
||||
mapping.Add("greek", new CharacterSet("greek", 1)); |
||||
mapping.Add("cp1250", new CharacterSet("windows-1250", 1)); |
||||
mapping.Add("win1250", mapping["cp1250"]); |
||||
mapping.Add("latin5", new CharacterSet("latin5", 1)); |
||||
mapping.Add("armscii8", mapping["latin1"]); |
||||
mapping.Add("utf8", new CharacterSet("utf-8", 3)); |
||||
mapping.Add("ucs2", new CharacterSet("UTF-16BE", 2)); |
||||
mapping.Add("cp866", new CharacterSet("cp866", 1)); |
||||
mapping.Add("keybcs2", mapping["latin1"]); |
||||
mapping.Add("macce", new CharacterSet("x-mac-ce", 1)); |
||||
mapping.Add("macroman", new CharacterSet("x-mac-romanian", 1)); |
||||
mapping.Add("cp852", new CharacterSet("ibm852", 2)); |
||||
mapping.Add("latin7", new CharacterSet("iso-8859-7", 1)); |
||||
mapping.Add("cp1251", new CharacterSet("windows-1251", 1)); |
||||
mapping.Add("win1251ukr", mapping["cp1251"]); |
||||
mapping.Add("cp1251csas", mapping["cp1251"]); |
||||
mapping.Add("cp1251cias", mapping["cp1251"]); |
||||
mapping.Add("win1251", mapping["cp1251"]); |
||||
mapping.Add("cp1256", new CharacterSet("cp1256", 1)); |
||||
mapping.Add("cp1257", new CharacterSet("windows-1257", 1)); |
||||
mapping.Add("ascii", new CharacterSet("us-ascii", 1)); |
||||
mapping.Add("usa7", mapping["ascii"]); |
||||
mapping.Add("binary", mapping["ascii"]); |
||||
mapping.Add("latin3", new CharacterSet("latin3", 1)); |
||||
mapping.Add("latin4", new CharacterSet("latin4", 1)); |
||||
mapping.Add("latin1_de", new CharacterSet("iso-8859-1", 1)); |
||||
mapping.Add("german1", new CharacterSet("iso-8859-1", 1)); |
||||
mapping.Add("danish", new CharacterSet("iso-8859-1", 1)); |
||||
mapping.Add("czech", new CharacterSet("iso-8859-2", 1)); |
||||
mapping.Add("hungarian", new CharacterSet("iso-8859-2", 1)); |
||||
mapping.Add("croat", new CharacterSet("iso-8859-2", 1)); |
||||
mapping.Add("latvian", new CharacterSet("iso-8859-13", 1)); |
||||
mapping.Add("latvian1", new CharacterSet("iso-8859-13", 1)); |
||||
mapping.Add("estonia", new CharacterSet("iso-8859-13", 1)); |
||||
mapping.Add("dos", new CharacterSet("ibm437", 1)); |
||||
} |
||||
|
||||
internal static void InitCollections(MySqlConnection connection) |
||||
{ |
||||
defaultCollations = new Dictionary<string, string>(); |
||||
maxLengths = new Dictionary<string, int>(); |
||||
|
||||
MySqlCommand cmd = new MySqlCommand("SHOW CHARSET", connection); |
||||
using (MySqlDataReader reader = cmd.ExecuteReader()) |
||||
{ |
||||
while (reader.Read()) |
||||
{ |
||||
defaultCollations.Add(reader.GetString(0), reader.GetString(2)); |
||||
maxLengths.Add(reader.GetString(0), Convert.ToInt32(reader.GetValue(3))); |
||||
} |
||||
} |
||||
} |
||||
|
||||
internal static string GetDefaultCollation(string charset, MySqlConnection connection) |
||||
{ |
||||
lock (lockObject) |
||||
{ |
||||
if (defaultCollations == null) |
||||
InitCollections(connection); |
||||
} |
||||
if (!defaultCollations.ContainsKey(charset)) |
||||
return null; |
||||
return defaultCollations[charset]; |
||||
} |
||||
|
||||
internal static int GetMaxLength(string charset, MySqlConnection connection) |
||||
{ |
||||
lock (lockObject) |
||||
{ |
||||
if (maxLengths == null) |
||||
InitCollections(connection); |
||||
} |
||||
|
||||
if (!maxLengths.ContainsKey(charset)) |
||||
return 1; |
||||
return maxLengths[charset]; |
||||
} |
||||
} |
||||
|
||||
internal class CharacterSet |
||||
{ |
||||
public string name; |
||||
public int byteCount; |
||||
|
||||
public CharacterSet(string name, int byteCount) |
||||
{ |
||||
this.name = name; |
||||
this.byteCount = byteCount; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,281 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.ComponentModel; |
||||
using System.Data.Common; |
||||
using System.Data; |
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using System.Collections; |
||||
using MySql.Data.Types; |
||||
using System.Globalization; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <include file='docs/MySqlCommandBuilder.xml' path='docs/class/*'/> |
||||
#if !CF |
||||
[ToolboxItem(false)] |
||||
[System.ComponentModel.DesignerCategory("Code")] |
||||
#endif |
||||
public sealed class MySqlCommandBuilder : DbCommandBuilder |
||||
{ |
||||
/// <include file='docs/MySqlCommandBuilder.xml' path='docs/Ctor/*'/> |
||||
public MySqlCommandBuilder() |
||||
{ |
||||
QuotePrefix = QuoteSuffix = "`"; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlCommandBuilder.xml' path='docs/Ctor2/*'/> |
||||
public MySqlCommandBuilder(MySqlDataAdapter adapter) |
||||
: this() |
||||
{ |
||||
DataAdapter = adapter; |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommandBuilder.xml' path='docs/DataAdapter/*'/> |
||||
public new MySqlDataAdapter DataAdapter |
||||
{ |
||||
get { return (MySqlDataAdapter)base.DataAdapter; } |
||||
set { base.DataAdapter = value; } |
||||
} |
||||
|
||||
#region Public Methods |
||||
|
||||
/// <summary> |
||||
/// Retrieves parameter information from the stored procedure specified |
||||
/// in the MySqlCommand and populates the Parameters collection of the |
||||
/// specified MySqlCommand object. |
||||
/// This method is not currently supported since stored procedures are |
||||
/// not available in MySql. |
||||
/// </summary> |
||||
/// <param name="command">The MySqlCommand referencing the stored |
||||
/// procedure from which the parameter information is to be derived. |
||||
/// The derived parameters are added to the Parameters collection of the |
||||
/// MySqlCommand.</param> |
||||
/// <exception cref="InvalidOperationException">The command text is not |
||||
/// a valid stored procedure name.</exception> |
||||
public static void DeriveParameters(MySqlCommand command) |
||||
{ |
||||
if (!command.Connection.driver.Version.isAtLeast(5, 0, 0)) |
||||
throw new MySqlException("DeriveParameters is not supported on MySQL versions " + |
||||
"prior to 5.0"); |
||||
|
||||
// retrieve the proc definitino from the cache. |
||||
string spName = command.CommandText; |
||||
if (spName.IndexOf(".") == -1) |
||||
spName = command.Connection.Database + "." + spName; |
||||
DataSet ds = command.Connection.ProcedureCache.GetProcedure(command.Connection, spName); |
||||
if (!ds.Tables.Contains("Procedure Parameters")) |
||||
throw new MySqlException(Resources.UnableToDeriveParameters); |
||||
|
||||
DataTable parameters = ds.Tables["Procedure Parameters"]; |
||||
DataTable procTable = ds.Tables["Procedures"]; |
||||
command.Parameters.Clear(); |
||||
foreach (DataRow row in parameters.Rows) |
||||
{ |
||||
MySqlParameter p = new MySqlParameter(); |
||||
p.ParameterName = String.Format("@{0}", row["PARAMETER_NAME"]); |
||||
if (row["ORDINAL_POSITION"].Equals(0) && p.ParameterName == "@") |
||||
p.ParameterName = "@RETURN_VALUE"; |
||||
p.Direction = GetDirection(row); |
||||
bool unsigned = StoredProcedure.GetFlags(row["DTD_IDENTIFIER"].ToString()).IndexOf("UNSIGNED") != -1; |
||||
bool real_as_float = procTable.Rows[0]["SQL_MODE"].ToString().IndexOf("REAL_AS_FLOAT") != -1; |
||||
p.MySqlDbType = MetaData.NameToType(row["DATA_TYPE"].ToString(), |
||||
unsigned, real_as_float, command.Connection); |
||||
if (!row["CHARACTER_MAXIMUM_LENGTH"].Equals(DBNull.Value)) |
||||
p.Size = (int)row["CHARACTER_MAXIMUM_LENGTH"]; |
||||
if (!row["NUMERIC_PRECISION"].Equals(DBNull.Value)) |
||||
p.Precision = Convert.ToByte(row["NUMERIC_PRECISION"]); |
||||
if (!row["NUMERIC_SCALE"].Equals(DBNull.Value)) |
||||
p.Scale = Convert.ToByte(row["NUMERIC_SCALE"]); |
||||
if (p.MySqlDbType == MySqlDbType.Set || p.MySqlDbType == MySqlDbType.Enum) |
||||
p.PossibleValues = GetPossibleValues(row); |
||||
command.Parameters.Add(p); |
||||
} |
||||
} |
||||
|
||||
private static List<string> GetPossibleValues(DataRow row) |
||||
{ |
||||
string[] types = new string[] { "ENUM", "SET" }; |
||||
string dtdIdentifier = row["DTD_IDENTIFIER"].ToString().Trim(); |
||||
|
||||
int index = 0; |
||||
for (; index < 2; index++) |
||||
if (dtdIdentifier.StartsWith(types[index], StringComparison.InvariantCultureIgnoreCase)) |
||||
break; |
||||
if (index == 2) return null; |
||||
dtdIdentifier = dtdIdentifier.Substring(types[index].Length).Trim(); |
||||
dtdIdentifier = dtdIdentifier.Trim('(', ')').Trim(); |
||||
|
||||
List<string> values = new List<string>(); |
||||
MySqlTokenizer tokenzier = new MySqlTokenizer(dtdIdentifier); |
||||
string token = tokenzier.NextToken(); |
||||
int start = tokenzier.StartIndex; |
||||
while (true) |
||||
{ |
||||
if (token == null || token == ",") |
||||
{ |
||||
int end = dtdIdentifier.Length - 1; |
||||
if (token == ",") |
||||
end = tokenzier.StartIndex; |
||||
|
||||
string value = dtdIdentifier.Substring(start, end - start).Trim('\'', '\"').Trim(); |
||||
values.Add(value); |
||||
start = tokenzier.StopIndex; |
||||
} |
||||
if (token == null) break; |
||||
token = tokenzier.NextToken(); |
||||
} |
||||
return values; |
||||
} |
||||
|
||||
private static ParameterDirection GetDirection(DataRow row) |
||||
{ |
||||
string mode = row["PARAMETER_MODE"].ToString(); |
||||
int ordinal = Convert.ToInt32(row["ORDINAL_POSITION"]); |
||||
|
||||
if (0 == ordinal) |
||||
return ParameterDirection.ReturnValue; |
||||
else if (mode == "IN") |
||||
return ParameterDirection.Input; |
||||
else if (mode == "OUT") |
||||
return ParameterDirection.Output; |
||||
return ParameterDirection.InputOutput; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the delete command. |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
public new MySqlCommand GetDeleteCommand() |
||||
{ |
||||
return (MySqlCommand)base.GetDeleteCommand(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the update command. |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
public new MySqlCommand GetUpdateCommand() |
||||
{ |
||||
return (MySqlCommand)base.GetUpdateCommand(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the insert command. |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
public new MySqlCommand GetInsertCommand() |
||||
{ |
||||
return (MySqlCommand)GetInsertCommand(false); |
||||
} |
||||
|
||||
public override string QuoteIdentifier(string unquotedIdentifier) |
||||
{ |
||||
if (unquotedIdentifier == null) throw new |
||||
ArgumentNullException("unquotedIdentifier"); |
||||
|
||||
// don't quote again if it is already quoted |
||||
if (unquotedIdentifier.StartsWith(QuotePrefix) && |
||||
unquotedIdentifier.EndsWith(QuoteSuffix)) |
||||
return unquotedIdentifier; |
||||
|
||||
unquotedIdentifier = unquotedIdentifier.Replace(QuotePrefix, QuotePrefix + QuotePrefix); |
||||
|
||||
return String.Format("{0}{1}{2}", QuotePrefix, unquotedIdentifier, QuoteSuffix); |
||||
} |
||||
|
||||
public override string UnquoteIdentifier(string quotedIdentifier) |
||||
{ |
||||
if (quotedIdentifier == null) throw new |
||||
ArgumentNullException("quotedIdentifier"); |
||||
|
||||
// don't unquote again if it is already unquoted |
||||
if (!quotedIdentifier.StartsWith(QuotePrefix) || |
||||
!quotedIdentifier.EndsWith(QuoteSuffix)) |
||||
return quotedIdentifier; |
||||
|
||||
if (quotedIdentifier.StartsWith(QuotePrefix)) |
||||
quotedIdentifier = quotedIdentifier.Substring(1); |
||||
if (quotedIdentifier.EndsWith(QuoteSuffix)) |
||||
quotedIdentifier = quotedIdentifier.Substring(0, quotedIdentifier.Length - 1); |
||||
|
||||
quotedIdentifier = quotedIdentifier.Replace(QuotePrefix + QuotePrefix, QuotePrefix); |
||||
|
||||
return quotedIdentifier; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
/// <summary> |
||||
/// |
||||
/// </summary> |
||||
/// <param name="parameterName"></param> |
||||
/// <returns></returns> |
||||
protected override string GetParameterName(string parameterName) |
||||
{ |
||||
StringBuilder sb = new StringBuilder(parameterName); |
||||
sb.Replace(" ", ""); |
||||
sb.Replace("/", "_per_"); |
||||
sb.Replace("-", "_"); |
||||
sb.Replace(")", "_cb_"); |
||||
sb.Replace("(", "_ob_"); |
||||
sb.Replace("%", "_pct_"); |
||||
sb.Replace("<", "_lt_"); |
||||
sb.Replace(">", "_gt_"); |
||||
sb.Replace(".", "_pt_"); |
||||
return String.Format("@{0}", sb.ToString()); |
||||
} |
||||
|
||||
protected override void ApplyParameterInfo(DbParameter parameter, DataRow row, |
||||
StatementType statementType, bool whereClause) |
||||
{ |
||||
((MySqlParameter)parameter).MySqlDbType = (MySqlDbType)row["ProviderType"]; |
||||
} |
||||
|
||||
protected override string GetParameterName(int parameterOrdinal) |
||||
{ |
||||
return String.Format("@p{0}", parameterOrdinal.ToString(CultureInfo.InvariantCulture)); |
||||
} |
||||
|
||||
protected override string GetParameterPlaceholder(int parameterOrdinal) |
||||
{ |
||||
return String.Format("@p{0}", parameterOrdinal.ToString(CultureInfo.InvariantCulture)); |
||||
} |
||||
|
||||
protected override void SetRowUpdatingHandler(DbDataAdapter adapter) |
||||
{ |
||||
MySqlDataAdapter myAdapter = (adapter as MySqlDataAdapter); |
||||
if (adapter != base.DataAdapter) |
||||
myAdapter.RowUpdating += new MySqlRowUpdatingEventHandler(RowUpdating); |
||||
else |
||||
myAdapter.RowUpdating -= new MySqlRowUpdatingEventHandler(RowUpdating); |
||||
} |
||||
|
||||
private void RowUpdating(object sender, MySqlRowUpdatingEventArgs args) |
||||
{ |
||||
base.RowUpdatingHandler(args); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,308 @@ |
||||
// Copyright (C) 2004-2007 MySQL AB |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.IO; |
||||
using zlib; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using MySql.Data.Common; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for CompressedStream. |
||||
/// </summary> |
||||
internal class CompressedStream : Stream |
||||
{ |
||||
// writing fields |
||||
private Stream baseStream; |
||||
private MemoryStream cache; |
||||
|
||||
// reading fields |
||||
private byte[] localByte; |
||||
private byte[] inBuffer; |
||||
private byte[] lengthBytes; |
||||
private WeakReference inBufferRef; |
||||
private int inPos; |
||||
private int maxInPos; |
||||
private ZInputStream zInStream; |
||||
|
||||
public CompressedStream(Stream baseStream) |
||||
{ |
||||
this.baseStream = baseStream; |
||||
localByte = new byte[1]; |
||||
lengthBytes = new byte[7]; |
||||
cache = new MemoryStream(); |
||||
inBufferRef = new WeakReference(inBuffer, false); |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
|
||||
public override bool CanRead |
||||
{ |
||||
get { return baseStream.CanRead; } |
||||
} |
||||
|
||||
public override bool CanWrite |
||||
{ |
||||
get { return baseStream.CanWrite; } |
||||
} |
||||
|
||||
public override bool CanSeek |
||||
{ |
||||
get { return baseStream.CanSeek; } |
||||
} |
||||
|
||||
public override long Length |
||||
{ |
||||
get { return baseStream.Length; } |
||||
} |
||||
|
||||
public override long Position |
||||
{ |
||||
get { return baseStream.Position; } |
||||
set { baseStream.Position = value; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public override void Close() |
||||
{ |
||||
baseStream.Close(); |
||||
base.Close(); |
||||
} |
||||
|
||||
public override void SetLength(long value) |
||||
{ |
||||
throw new NotSupportedException(Resources.CSNoSetLength); |
||||
} |
||||
|
||||
public override int ReadByte() |
||||
{ |
||||
try |
||||
{ |
||||
Read(localByte, 0, 1); |
||||
return localByte[0]; |
||||
} |
||||
catch (EndOfStreamException) |
||||
{ |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
public override bool CanTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return baseStream.CanTimeout; |
||||
} |
||||
} |
||||
|
||||
public override int ReadTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return baseStream.ReadTimeout; |
||||
} |
||||
set |
||||
{ |
||||
baseStream.ReadTimeout = value; |
||||
} |
||||
} |
||||
|
||||
public override int WriteTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return baseStream.WriteTimeout; |
||||
} |
||||
set |
||||
{ |
||||
baseStream.WriteTimeout = value; |
||||
} |
||||
} |
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) |
||||
{ |
||||
if (buffer == null) |
||||
throw new ArgumentNullException("buffer", Resources.BufferCannotBeNull); |
||||
if (offset < 0 || offset >= buffer.Length) |
||||
throw new ArgumentOutOfRangeException("offset", Resources.OffsetMustBeValid); |
||||
if ((offset + count) > buffer.Length) |
||||
throw new ArgumentException(Resources.BufferNotLargeEnough, "buffer"); |
||||
|
||||
if (inPos == maxInPos) |
||||
PrepareNextPacket(); |
||||
|
||||
int countToRead = Math.Min(count, maxInPos - inPos); |
||||
int countRead; |
||||
if (zInStream != null) |
||||
countRead = zInStream.read(buffer, offset, countToRead); |
||||
else |
||||
countRead = baseStream.Read(buffer, offset, countToRead); |
||||
inPos += countRead; |
||||
|
||||
// release the weak reference |
||||
if (inPos == maxInPos) |
||||
{ |
||||
zInStream = null; |
||||
if (!Platform.IsMono()) |
||||
{ |
||||
inBufferRef = new WeakReference(inBuffer, false); |
||||
inBuffer = null; |
||||
} |
||||
} |
||||
|
||||
return countRead; |
||||
} |
||||
|
||||
private void PrepareNextPacket() |
||||
{ |
||||
MySqlStream.ReadFully(baseStream, lengthBytes, 0, 7); |
||||
int compressedLength = lengthBytes[0] + (lengthBytes[1] << 8) + (lengthBytes[2] << 16); |
||||
// lengthBytes[3] is seq |
||||
int unCompressedLength = lengthBytes[4] + (lengthBytes[5] << 8) + |
||||
(lengthBytes[6] << 16); |
||||
|
||||
if (unCompressedLength == 0) |
||||
{ |
||||
unCompressedLength = compressedLength; |
||||
zInStream = null; |
||||
} |
||||
else |
||||
{ |
||||
ReadNextPacket(compressedLength); |
||||
MemoryStream ms = new MemoryStream(inBuffer); |
||||
zInStream = new ZInputStream(ms); |
||||
zInStream.maxInput = compressedLength; |
||||
} |
||||
|
||||
inPos = 0; |
||||
maxInPos = unCompressedLength; |
||||
} |
||||
|
||||
private void ReadNextPacket(int len) |
||||
{ |
||||
if (!Platform.IsMono()) |
||||
inBuffer = inBufferRef.Target as byte[]; |
||||
|
||||
if (inBuffer == null || inBuffer.Length < len) |
||||
inBuffer = new byte[len]; |
||||
MySqlStream.ReadFully(baseStream, inBuffer, 0, len); |
||||
} |
||||
|
||||
private MemoryStream CompressCache() |
||||
{ |
||||
// small arrays almost never yeild a benefit from compressing |
||||
if (cache.Length < 50) |
||||
return null; |
||||
|
||||
byte[] cacheBytes = cache.GetBuffer(); |
||||
MemoryStream compressedBuffer = new MemoryStream(); |
||||
ZOutputStream zos = new ZOutputStream(compressedBuffer, zlibConst.Z_DEFAULT_COMPRESSION); |
||||
zos.Write(cacheBytes, 0, (int) cache.Length); |
||||
zos.finish(); |
||||
|
||||
// if the compression hasn't helped, then just return null |
||||
if (compressedBuffer.Length >= cache.Length) |
||||
return null; |
||||
return compressedBuffer; |
||||
} |
||||
|
||||
private void CompressAndSendCache() |
||||
{ |
||||
long compressedLength, uncompressedLength; |
||||
|
||||
// we need to save the sequence byte that is written |
||||
byte[] cacheBuffer = cache.GetBuffer(); |
||||
byte seq = cacheBuffer[3]; |
||||
cacheBuffer[3] = 0; |
||||
|
||||
// first we compress our current cache |
||||
MemoryStream compressedBuffer = CompressCache(); |
||||
|
||||
// now we set our compressed and uncompressed lengths |
||||
// based on if our compression is going to help or not |
||||
if (compressedBuffer == null) |
||||
{ |
||||
compressedLength = cache.Length; |
||||
uncompressedLength = 0; |
||||
} |
||||
else |
||||
{ |
||||
compressedLength = compressedBuffer.Length; |
||||
uncompressedLength = cache.Length; |
||||
} |
||||
|
||||
baseStream.WriteByte((byte) (compressedLength & 0xff)); |
||||
baseStream.WriteByte((byte) ((compressedLength >> 8) & 0xff)); |
||||
baseStream.WriteByte((byte) ((compressedLength >> 16) & 0Xff)); |
||||
baseStream.WriteByte(seq); |
||||
baseStream.WriteByte((byte) (uncompressedLength & 0xff)); |
||||
baseStream.WriteByte((byte) ((uncompressedLength >> 8) & 0xff)); |
||||
baseStream.WriteByte((byte) ((uncompressedLength >> 16) & 0Xff)); |
||||
|
||||
if (compressedBuffer == null) |
||||
baseStream.Write(cacheBuffer, 0, (int) cache.Length); |
||||
else |
||||
{ |
||||
byte[] compressedBytes = compressedBuffer.GetBuffer(); |
||||
baseStream.Write(compressedBytes, 0, (int) compressedBuffer.Length); |
||||
} |
||||
|
||||
baseStream.Flush(); |
||||
|
||||
cache.SetLength(0); |
||||
} |
||||
|
||||
public override void Flush() |
||||
{ |
||||
if (!InputDone()) return; |
||||
|
||||
CompressAndSendCache(); |
||||
} |
||||
|
||||
private bool InputDone() |
||||
{ |
||||
// if we have not done so yet, see if we can calculate how many bytes we are expecting |
||||
if (cache.Length < 4) return false; |
||||
byte[] buf = cache.GetBuffer(); |
||||
int expectedLen = buf[0] + (buf[1] << 8) + (buf[2] << 16); |
||||
if (cache.Length < (expectedLen + 4)) return false; |
||||
return true; |
||||
} |
||||
|
||||
public override void WriteByte(byte value) |
||||
{ |
||||
cache.WriteByte(value); |
||||
} |
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) |
||||
{ |
||||
cache.Write(buffer, offset, count); |
||||
} |
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) |
||||
{ |
||||
return baseStream.Seek(offset, origin); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,867 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.ComponentModel; |
||||
using System.Data; |
||||
using System.Data.Common; |
||||
#if !CF |
||||
using System.Drawing; |
||||
using System.Drawing.Design; |
||||
using System.Transactions; |
||||
#endif |
||||
using System.Text; |
||||
using IsolationLevel=System.Data.IsolationLevel; |
||||
using MySql.Data.Common; |
||||
using System.Diagnostics; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <include file='docs/MySqlConnection.xml' path='docs/ClassSummary/*'/> |
||||
#if !CF |
||||
[ToolboxBitmap(typeof (MySqlConnection), "MySqlClient.resources.connection.bmp")] |
||||
[DesignerCategory("Code")] |
||||
[ToolboxItem(true)] |
||||
#endif |
||||
public sealed class MySqlConnection : DbConnection, ICloneable |
||||
{ |
||||
internal ConnectionState connectionState; |
||||
internal Driver driver; |
||||
private MySqlConnectionStringBuilder settings; |
||||
private bool hasBeenOpen; |
||||
private SchemaProvider schemaProvider; |
||||
private ProcedureCache procedureCache; |
||||
#if !CF |
||||
private PerformanceMonitor perfMonitor; |
||||
#endif |
||||
private bool abortOnTimeout; |
||||
private string database; |
||||
private int commandTimeout; |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/InfoMessage/*'/> |
||||
public event MySqlInfoMessageEventHandler InfoMessage; |
||||
|
||||
private static Cache<string, MySqlConnectionStringBuilder> connectionStringCache = |
||||
new Cache<string, MySqlConnectionStringBuilder>(0, 25); |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/DefaultCtor/*'/> |
||||
public MySqlConnection() |
||||
{ |
||||
//TODO: add event data to StateChange docs |
||||
settings = new MySqlConnectionStringBuilder(); |
||||
database = String.Empty; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/Ctor1/*'/> |
||||
public MySqlConnection(string connectionString) |
||||
: this() |
||||
{ |
||||
ConnectionString = connectionString; |
||||
} |
||||
|
||||
#region Interal Methods & Properties |
||||
|
||||
#if !CF |
||||
internal PerformanceMonitor PerfMonitor |
||||
{ |
||||
get { return perfMonitor; } |
||||
} |
||||
|
||||
#endif |
||||
|
||||
internal ProcedureCache ProcedureCache |
||||
{ |
||||
get { return procedureCache; } |
||||
} |
||||
|
||||
internal MySqlConnectionStringBuilder Settings |
||||
{ |
||||
get { return settings; } |
||||
} |
||||
|
||||
internal MySqlDataReader Reader |
||||
{ |
||||
get |
||||
{ |
||||
if (driver == null) |
||||
return null; |
||||
return driver.reader; |
||||
|
||||
} |
||||
|
||||
set |
||||
{ |
||||
driver.reader = value; |
||||
} |
||||
} |
||||
|
||||
internal void OnInfoMessage(MySqlInfoMessageEventArgs args) |
||||
{ |
||||
if (InfoMessage != null) |
||||
{ |
||||
InfoMessage(this, args); |
||||
} |
||||
} |
||||
|
||||
|
||||
internal bool SoftClosed |
||||
{ |
||||
get |
||||
{ |
||||
#if !CF |
||||
return (State == ConnectionState.Closed) && |
||||
driver != null && |
||||
driver.CurrentTransaction != null; |
||||
#else |
||||
return false; |
||||
#endif |
||||
} |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Properties |
||||
|
||||
/// <summary> |
||||
/// Returns the id of the server thread this connection is executing on |
||||
/// </summary> |
||||
#if !CF |
||||
[Browsable(false)] |
||||
#endif |
||||
public int ServerThread |
||||
{ |
||||
get { return driver.ThreadID; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the name of the MySQL server to which to connect. |
||||
/// </summary> |
||||
#if !CF |
||||
[Browsable(true)] |
||||
#endif |
||||
public override string DataSource |
||||
{ |
||||
get { return settings.Server; } |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/ConnectionTimeout/*'/> |
||||
#if !CF |
||||
[Browsable(true)] |
||||
#endif |
||||
public override int ConnectionTimeout |
||||
{ |
||||
get { return (int) settings.ConnectionTimeout; } |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/Database/*'/> |
||||
#if !CF |
||||
[Browsable(true)] |
||||
#endif |
||||
public override string Database |
||||
{ |
||||
get { return database; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Indicates if this connection should use compression when communicating with the server. |
||||
/// </summary> |
||||
#if !CF |
||||
[Browsable(false)] |
||||
#endif |
||||
public bool UseCompression |
||||
{ |
||||
get { return settings.UseCompression; } |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/State/*'/> |
||||
#if !CF |
||||
[Browsable(false)] |
||||
#endif |
||||
public override ConnectionState State |
||||
{ |
||||
get { return connectionState; } |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/ServerVersion/*'/> |
||||
#if !CF |
||||
[Browsable(false)] |
||||
#endif |
||||
public override string ServerVersion |
||||
{ |
||||
get { return driver.Version.ToString(); } |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/ConnectionString/*'/> |
||||
#if !CF |
||||
[Editor("MySql.Data.MySqlClient.Design.ConnectionStringTypeEditor,MySqlClient.Design", typeof (UITypeEditor))] |
||||
[Browsable(true)] |
||||
[Category("Data")] |
||||
[Description( |
||||
"Information used to connect to a DataSource, such as 'Server=xxx;UserId=yyy;Password=zzz;Database=dbdb'.")] |
||||
#endif |
||||
public override string ConnectionString |
||||
{ |
||||
get |
||||
{ |
||||
// Always return exactly what the user set. |
||||
// Security-sensitive information may be removed. |
||||
return settings.GetConnectionString(!hasBeenOpen || settings.PersistSecurityInfo); |
||||
} |
||||
set |
||||
{ |
||||
if (State != ConnectionState.Closed) |
||||
throw new MySqlException( |
||||
"Not allowed to change the 'ConnectionString' property while the connection (state=" + State + |
||||
")."); |
||||
|
||||
MySqlConnectionStringBuilder newSettings; |
||||
lock (connectionStringCache) |
||||
{ |
||||
if (value == null) |
||||
newSettings = new MySqlConnectionStringBuilder(); |
||||
else |
||||
{ |
||||
newSettings = (MySqlConnectionStringBuilder)connectionStringCache[value]; |
||||
if (null == newSettings) |
||||
{ |
||||
newSettings = new MySqlConnectionStringBuilder(value); |
||||
connectionStringCache.Add(value, newSettings); |
||||
} |
||||
} |
||||
} |
||||
|
||||
settings = newSettings; |
||||
|
||||
if (settings.Database != null && settings.Database.Length > 0) |
||||
this.database = settings.Database; |
||||
|
||||
if (driver != null) |
||||
driver.Settings = newSettings; |
||||
} |
||||
} |
||||
|
||||
#if !CF && !__MonoCS__ |
||||
|
||||
protected override DbProviderFactory DbProviderFactory |
||||
{ |
||||
get |
||||
{ |
||||
return MySqlClientFactory.Instance; |
||||
} |
||||
} |
||||
|
||||
#endif |
||||
|
||||
#endregion |
||||
|
||||
#region Transactions |
||||
|
||||
#if !MONO && !CF |
||||
/// <summary> |
||||
/// Enlists in the specified transaction. |
||||
/// </summary> |
||||
/// <param name="transaction"> |
||||
/// A reference to an existing <see cref="System.Transactions.Transaction"/> in which to enlist. |
||||
/// </param> |
||||
public override void EnlistTransaction(Transaction transaction) |
||||
{ |
||||
// enlisting in the null transaction is a noop |
||||
if (transaction == null) |
||||
return; |
||||
|
||||
// guard against trying to enlist in more than one transaction |
||||
if (driver.CurrentTransaction != null) |
||||
{ |
||||
if (driver.CurrentTransaction.BaseTransaction == transaction) |
||||
return; |
||||
|
||||
throw new MySqlException("Already enlisted"); |
||||
} |
||||
|
||||
// now see if we need to swap out drivers. We would need to do this since |
||||
// we have to make sure all ops for a given transaction are done on the |
||||
// same physical connection. |
||||
Driver existingDriver = DriverTransactionManager.GetDriverInTransaction(transaction); |
||||
if (existingDriver != null) |
||||
{ |
||||
// we can't allow more than one driver to contribute to the same connection |
||||
if (existingDriver.IsInActiveUse) |
||||
throw new NotSupportedException(Resources.MultipleConnectionsInTransactionNotSupported); |
||||
|
||||
// there is an existing driver and it's not being currently used. |
||||
// now we need to see if it is using the same connection string |
||||
string text1 = existingDriver.Settings.ConnectionString; |
||||
string text2 = Settings.ConnectionString; |
||||
if (String.Compare(text1, text2, true) != 0) |
||||
throw new NotSupportedException(Resources.MultipleConnectionsInTransactionNotSupported); |
||||
|
||||
// close existing driver |
||||
// set this new driver as our existing driver |
||||
CloseFully(); |
||||
driver = existingDriver; |
||||
} |
||||
|
||||
if (driver.CurrentTransaction == null) |
||||
{ |
||||
MySqlPromotableTransaction t = new MySqlPromotableTransaction(this, transaction); |
||||
if (!transaction.EnlistPromotableSinglePhase(t)) |
||||
throw new NotSupportedException(Resources.DistributedTxnNotSupported); |
||||
|
||||
driver.CurrentTransaction = t; |
||||
DriverTransactionManager.SetDriverInTransaction(driver); |
||||
driver.IsInActiveUse = true; |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/BeginTransaction/*'/> |
||||
public new MySqlTransaction BeginTransaction() |
||||
{ |
||||
return BeginTransaction(IsolationLevel.RepeatableRead); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/BeginTransaction1/*'/> |
||||
public new MySqlTransaction BeginTransaction(IsolationLevel iso) |
||||
{ |
||||
//TODO: check note in help |
||||
if (State != ConnectionState.Open) |
||||
throw new InvalidOperationException(Resources.ConnectionNotOpen); |
||||
|
||||
// First check to see if we are in a current transaction |
||||
if (driver.HasStatus(ServerStatusFlags.InTransaction)) |
||||
throw new InvalidOperationException(Resources.NoNestedTransactions); |
||||
|
||||
MySqlTransaction t = new MySqlTransaction(this, iso); |
||||
|
||||
MySqlCommand cmd = new MySqlCommand("", this); |
||||
|
||||
cmd.CommandText = "SET SESSION TRANSACTION ISOLATION LEVEL "; |
||||
switch (iso) |
||||
{ |
||||
case IsolationLevel.ReadCommitted: |
||||
cmd.CommandText += "READ COMMITTED"; |
||||
break; |
||||
case IsolationLevel.ReadUncommitted: |
||||
cmd.CommandText += "READ UNCOMMITTED"; |
||||
break; |
||||
case IsolationLevel.RepeatableRead: |
||||
cmd.CommandText += "REPEATABLE READ"; |
||||
break; |
||||
case IsolationLevel.Serializable: |
||||
cmd.CommandText += "SERIALIZABLE"; |
||||
break; |
||||
case IsolationLevel.Chaos: |
||||
throw new NotSupportedException(Resources.ChaosNotSupported); |
||||
} |
||||
|
||||
cmd.ExecuteNonQuery(); |
||||
|
||||
cmd.CommandText = "BEGIN"; |
||||
cmd.ExecuteNonQuery(); |
||||
|
||||
return t; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/ChangeDatabase/*'/> |
||||
public override void ChangeDatabase(string databaseName) |
||||
{ |
||||
if (databaseName == null || databaseName.Trim().Length == 0) |
||||
throw new ArgumentException(Resources.ParameterIsInvalid, "databaseName"); |
||||
|
||||
if (State != ConnectionState.Open) |
||||
throw new InvalidOperationException(Resources.ConnectionNotOpen); |
||||
|
||||
// This lock prevents promotable transaction rollback to run |
||||
// in parallel |
||||
lock (driver) |
||||
{ |
||||
#if !CF |
||||
if (Transaction.Current != null && |
||||
Transaction.Current.TransactionInformation.Status == TransactionStatus.Aborted) |
||||
{ |
||||
throw new TransactionAbortedException(); |
||||
} |
||||
#endif |
||||
// We use default command timeout for SetDatabase |
||||
using (new CommandTimer(this, (int)Settings.DefaultCommandTimeout)) |
||||
{ |
||||
driver.SetDatabase(databaseName); |
||||
} |
||||
} |
||||
this.database = databaseName; |
||||
} |
||||
|
||||
internal void SetState(ConnectionState newConnectionState, bool broadcast) |
||||
{ |
||||
if (newConnectionState == connectionState && !broadcast) |
||||
return; |
||||
ConnectionState oldConnectionState = connectionState; |
||||
connectionState = newConnectionState; |
||||
if (broadcast) |
||||
OnStateChange(new StateChangeEventArgs(oldConnectionState, connectionState)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Ping |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
public bool Ping() |
||||
{ |
||||
if (driver != null && driver.Ping()) |
||||
return true; |
||||
driver = null; |
||||
SetState(ConnectionState.Closed, true); |
||||
return false; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/Open/*'/> |
||||
public override void Open() |
||||
{ |
||||
if (State == ConnectionState.Open) |
||||
throw new InvalidOperationException(Resources.ConnectionAlreadyOpen); |
||||
|
||||
SetState(ConnectionState.Connecting, true); |
||||
|
||||
#if !CF |
||||
// if we are auto enlisting in a current transaction, then we will be |
||||
// treating the connection as pooled |
||||
if (settings.AutoEnlist && Transaction.Current != null) |
||||
{ |
||||
driver = DriverTransactionManager.GetDriverInTransaction(Transaction.Current); |
||||
if (driver != null && |
||||
(driver.IsInActiveUse || |
||||
!driver.Settings.EquivalentTo(this.Settings))) |
||||
throw new NotSupportedException(Resources.MultipleConnectionsInTransactionNotSupported); |
||||
} |
||||
#endif |
||||
|
||||
try |
||||
{ |
||||
if (settings.Pooling) |
||||
{ |
||||
MySqlPool pool = MySqlPoolManager.GetPool(settings); |
||||
if (driver == null) |
||||
driver = pool.GetConnection(); |
||||
procedureCache = pool.ProcedureCache; |
||||
} |
||||
else |
||||
{ |
||||
if (driver == null) |
||||
driver = Driver.Create(settings); |
||||
procedureCache = new ProcedureCache((int) settings.ProcedureCacheSize); |
||||
} |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
SetState(ConnectionState.Closed, true); |
||||
throw; |
||||
} |
||||
|
||||
// if the user is using old syntax, let them know |
||||
if (driver.Settings.UseOldSyntax) |
||||
MySqlTrace.LogWarning(ServerThread, |
||||
"You are using old syntax that will be removed in future versions"); |
||||
|
||||
SetState(ConnectionState.Open, false); |
||||
driver.Configure(this); |
||||
if (settings.Database != null && settings.Database != String.Empty) |
||||
ChangeDatabase(settings.Database); |
||||
|
||||
// setup our schema provider |
||||
if (driver.Version.isAtLeast(5, 0, 0)) |
||||
schemaProvider = new ISSchemaProvider(this); |
||||
else |
||||
schemaProvider = new SchemaProvider(this); |
||||
#if !CF |
||||
perfMonitor = new PerformanceMonitor(this); |
||||
#endif |
||||
|
||||
// if we are opening up inside a current transaction, then autoenlist |
||||
// TODO: control this with a connection string option |
||||
#if !MONO && !CF |
||||
if (Transaction.Current != null && settings.AutoEnlist) |
||||
EnlistTransaction(Transaction.Current); |
||||
#endif |
||||
|
||||
hasBeenOpen = true; |
||||
SetState(ConnectionState.Open, true); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/CreateCommand/*'/> |
||||
public new MySqlCommand CreateCommand() |
||||
{ |
||||
// Return a new instance of a command object. |
||||
MySqlCommand c = new MySqlCommand(); |
||||
c.Connection = this; |
||||
return c; |
||||
} |
||||
|
||||
#region ICloneable |
||||
|
||||
/// <summary> |
||||
/// Creates a new MySqlConnection object with the exact same ConnectionString value |
||||
/// </summary> |
||||
/// <returns>A cloned MySqlConnection object</returns> |
||||
public MySqlConnection Clone() |
||||
{ |
||||
MySqlConnection clone = new MySqlConnection(); |
||||
string connectionString = settings.ConnectionString; |
||||
if (connectionString != null) |
||||
clone.ConnectionString = connectionString; |
||||
return clone; |
||||
} |
||||
|
||||
object ICloneable.Clone() |
||||
{ |
||||
return this.Clone(); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region IDisposeable |
||||
|
||||
protected override void Dispose(bool disposing) |
||||
{ |
||||
if (State == ConnectionState.Open) |
||||
Close(); |
||||
base.Dispose(disposing); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) |
||||
{ |
||||
if (isolationLevel == IsolationLevel.Unspecified) |
||||
return BeginTransaction(); |
||||
return BeginTransaction(isolationLevel); |
||||
} |
||||
|
||||
protected override DbCommand CreateDbCommand() |
||||
{ |
||||
return CreateCommand(); |
||||
} |
||||
|
||||
internal void Abort() |
||||
{ |
||||
try |
||||
{ |
||||
if (settings.Pooling) |
||||
MySqlPoolManager.ReleaseConnection(driver); |
||||
else |
||||
driver.Close(); |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
} |
||||
SetState(ConnectionState.Closed, true); |
||||
} |
||||
|
||||
internal void CloseFully() |
||||
{ |
||||
if (settings.Pooling && driver.IsOpen) |
||||
{ |
||||
// if we are in a transaction, roll it back |
||||
if (driver.HasStatus(ServerStatusFlags.InTransaction)) |
||||
{ |
||||
MySqlTransaction t = new MySqlTransaction(this, IsolationLevel.Unspecified); |
||||
t.Rollback(); |
||||
} |
||||
|
||||
MySqlPoolManager.ReleaseConnection(driver); |
||||
} |
||||
else |
||||
driver.Close(); |
||||
driver = null; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/Close/*'/> |
||||
public override void Close() |
||||
{ |
||||
if (State == ConnectionState.Closed) return; |
||||
|
||||
if (Reader != null) |
||||
Reader.Close(); |
||||
|
||||
// if the reader was opened with CloseConnection then driver |
||||
// will be null on the second time through |
||||
if (driver != null) |
||||
{ |
||||
#if !CF |
||||
if (driver.CurrentTransaction == null) |
||||
#endif |
||||
CloseFully(); |
||||
#if !CF |
||||
else |
||||
driver.IsInActiveUse = false; |
||||
#endif |
||||
} |
||||
|
||||
SetState(ConnectionState.Closed, true); |
||||
} |
||||
|
||||
internal string CurrentDatabase() |
||||
{ |
||||
if (Database != null && Database.Length > 0) |
||||
return Database; |
||||
MySqlCommand cmd = new MySqlCommand("SELECT database()", this); |
||||
return cmd.ExecuteScalar().ToString(); |
||||
} |
||||
|
||||
|
||||
|
||||
internal void HandleTimeout(TimeoutException tex) |
||||
{ |
||||
bool isFatal = false; |
||||
|
||||
if (abortOnTimeout) |
||||
{ |
||||
// Special connection started to cancel a query. |
||||
// Timeout handler is disabled to prevent recursive connection |
||||
// spawning when original query and KILL time out. |
||||
Abort(); |
||||
throw new MySqlException(Resources.Timeout, true , tex); |
||||
} |
||||
|
||||
try |
||||
{ |
||||
|
||||
// Do a fast cancel.The reason behind small values for connection |
||||
// and command timeout is that we do not want user to wait longer |
||||
// after command has already expired. |
||||
// Microsoft's SqlClient seems to be using 5 seconds timeouts |
||||
// here as well. |
||||
// Read the error packet with "interrupted" message. |
||||
CancelQuery(5); |
||||
driver.ResetTimeout(5000); |
||||
if (Reader != null) |
||||
{ |
||||
Reader.Close(); |
||||
Reader = null; |
||||
} |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
MySqlTrace.LogWarning(ServerThread, "Could not kill query in timeout handler, " + |
||||
" aborting connection. Exception was " + ex.Message); |
||||
Abort(); |
||||
isFatal = true; |
||||
} |
||||
throw new MySqlException(Resources.Timeout, isFatal, tex); |
||||
} |
||||
|
||||
public void CancelQuery(int timeout) |
||||
{ |
||||
if (!driver.Version.isAtLeast(5, 0, 0)) |
||||
throw new NotSupportedException(Resources.CancelNotSupported); |
||||
|
||||
MySqlConnectionStringBuilder cb = new MySqlConnectionStringBuilder( |
||||
Settings.ConnectionString); |
||||
cb.Pooling = false; |
||||
cb.ConnectionTimeout = (uint) timeout; |
||||
|
||||
using(MySqlConnection c = new MySqlConnection(cb.ConnectionString)) |
||||
{ |
||||
c.abortOnTimeout = true; |
||||
c.Open(); |
||||
string commandText = "KILL QUERY " + ServerThread; |
||||
MySqlCommand cmd = new MySqlCommand(commandText, c); |
||||
cmd.CommandTimeout = timeout; |
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
} |
||||
|
||||
#region Routines for timeout support. |
||||
|
||||
// Problem description: |
||||
// Sometimes, ExecuteReader is called recursively. This is the case if |
||||
// command behaviors are used and we issue "set sql_select_limit" |
||||
// before and after command. This is also the case with prepared |
||||
// statements , where we set session variables. In these situations, we |
||||
// have to prevent recursive ExecuteReader calls from overwriting |
||||
// timeouts set by the top level command. |
||||
|
||||
// To solve the problem, SetCommandTimeout() and ClearCommandTimeout() are |
||||
// introduced . Query timeout here is "sticky", that is once set with |
||||
// SetCommandTimeout, it only be overwritten after ClearCommandTimeout |
||||
// (SetCommandTimeout would return false if it timeout has not been |
||||
// cleared). |
||||
|
||||
// The proposed usage pattern of there routines is following: |
||||
// When timed operations starts, issue SetCommandTimeout(). When it |
||||
// finishes, issue ClearCommandTimeout(), but _only_ if call to |
||||
// SetCommandTimeout() was successful. |
||||
|
||||
|
||||
/// <summary> |
||||
/// Sets query timeout. If timeout has been set prior and not |
||||
/// yet cleared ClearCommandTimeout(), it has no effect. |
||||
/// </summary> |
||||
/// <param name="value">timeout in seconds</param> |
||||
/// <returns>true if </returns> |
||||
internal bool SetCommandTimeout(int value) |
||||
{ |
||||
if (!hasBeenOpen) |
||||
// Connection timeout is handled by driver |
||||
return false; |
||||
|
||||
if (commandTimeout != 0) |
||||
// someone is trying to set a timeout while command is already |
||||
// running. It could be for example recursive call to ExecuteReader |
||||
// Ignore the request, as only top-level (non-recursive commands) |
||||
// can set timeouts. |
||||
return false; |
||||
|
||||
if (driver == null) |
||||
return false; |
||||
|
||||
commandTimeout = value; |
||||
driver.ResetTimeout(commandTimeout * 1000); |
||||
return true; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Clears query timeout, allowing next SetCommandTimeout() to succeed. |
||||
/// </summary> |
||||
internal void ClearCommandTimeout() |
||||
{ |
||||
if (!hasBeenOpen) |
||||
return; |
||||
commandTimeout = 0; |
||||
if (driver != null) |
||||
{ |
||||
driver.ResetTimeout(0); |
||||
} |
||||
} |
||||
#endregion |
||||
|
||||
|
||||
#region GetSchema Support |
||||
|
||||
/// <summary> |
||||
/// Returns schema information for the data source of this <see cref="DbConnection"/>. |
||||
/// </summary> |
||||
/// <returns>A <see cref="DataTable"/> that contains schema information. </returns> |
||||
public override DataTable GetSchema() |
||||
{ |
||||
return GetSchema(null); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns schema information for the data source of this |
||||
/// <see cref="DbConnection"/> using the specified string for the schema name. |
||||
/// </summary> |
||||
/// <param name="collectionName">Specifies the name of the schema to return. </param> |
||||
/// <returns>A <see cref="DataTable"/> that contains schema information. </returns> |
||||
public override DataTable GetSchema(string collectionName) |
||||
{ |
||||
if (collectionName == null) |
||||
collectionName = SchemaProvider.MetaCollection; |
||||
|
||||
return GetSchema(collectionName, null); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns schema information for the data source of this <see cref="DbConnection"/> |
||||
/// using the specified string for the schema name and the specified string array |
||||
/// for the restriction values. |
||||
/// </summary> |
||||
/// <param name="collectionName">Specifies the name of the schema to return.</param> |
||||
/// <param name="restrictionValues">Specifies a set of restriction values for the requested schema.</param> |
||||
/// <returns>A <see cref="DataTable"/> that contains schema information.</returns> |
||||
public override DataTable GetSchema(string collectionName, string[] restrictionValues) |
||||
{ |
||||
if (collectionName == null) |
||||
collectionName = SchemaProvider.MetaCollection; |
||||
|
||||
string[] restrictions = schemaProvider.CleanRestrictions(restrictionValues); |
||||
DataTable dt = schemaProvider.GetSchema(collectionName, restrictions); |
||||
return dt; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Pool Routines |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/ClearPool/*'/> |
||||
public static void ClearPool(MySqlConnection connection) |
||||
{ |
||||
MySqlPoolManager.ClearPool(connection.Settings); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlConnection.xml' path='docs/ClearAllPools/*'/> |
||||
public static void ClearAllPools() |
||||
{ |
||||
MySqlPoolManager.ClearAllPools(); |
||||
} |
||||
|
||||
#endregion |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Represents the method that will handle the <see cref="MySqlConnection.InfoMessage"/> event of a |
||||
/// <see cref="MySqlConnection"/>. |
||||
/// </summary> |
||||
public delegate void MySqlInfoMessageEventHandler(object sender, MySqlInfoMessageEventArgs args); |
||||
|
||||
/// <summary> |
||||
/// Provides data for the InfoMessage event. This class cannot be inherited. |
||||
/// </summary> |
||||
public class MySqlInfoMessageEventArgs : EventArgs |
||||
{ |
||||
/// <summary> |
||||
/// |
||||
/// </summary> |
||||
public MySqlError[] errors; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// IDisposable wrapper around SetCommandTimeout and ClearCommandTimeout |
||||
/// functionality |
||||
/// </summary> |
||||
internal class CommandTimer:IDisposable |
||||
{ |
||||
bool timeoutSet; |
||||
MySqlConnection connection; |
||||
|
||||
public CommandTimer(MySqlConnection connection, int timeout) |
||||
{ |
||||
this.connection = connection; |
||||
if (connection != null) |
||||
{ |
||||
timeoutSet = connection.SetCommandTimeout(timeout); |
||||
} |
||||
} |
||||
|
||||
#region IDisposable Members |
||||
public void Dispose() |
||||
{ |
||||
if (timeoutSet) |
||||
{ |
||||
timeoutSet = false; |
||||
connection.ClearCommandTimeout(); |
||||
connection = null; |
||||
} |
||||
} |
||||
#endregion |
||||
} |
||||
} |
@ -0,0 +1,338 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Globalization; |
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
//using System.Security.Cryptography; |
||||
//#if CF |
||||
//using OpenNETCF.Security.Cryptography; |
||||
//#endif |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for Crypt. |
||||
/// </summary> |
||||
internal class Crypt |
||||
{ |
||||
// private ctor to prevent creating a default one |
||||
private Crypt() |
||||
{ |
||||
} |
||||
|
||||
/* private void Create41Password( string password ) |
||||
{ |
||||
SHA1 sha = new SHA1CryptoServiceProvider(); |
||||
byte[] firstPassBytes = sha.ComputeHash( System.Text.Encoding.Default.GetBytes( password )); |
||||
|
||||
byte[] salt = packet.GetBuffer(); |
||||
byte[] input = new byte[ firstPassBytes.Length + 4 ]; |
||||
salt.CopyTo( input, 0 ); |
||||
firstPassBytes.CopyTo( input, 4 ); |
||||
byte[] outPass = new byte[100]; |
||||
byte[] secondPassBytes = sha.ComputeHash( input ); |
||||
|
||||
byte[] cryptSalt = new byte[20]; |
||||
Security.ArrayCrypt( salt, 4, cryptSalt, 0, secondPassBytes, 20 ); |
||||
|
||||
Security.ArrayCrypt( cryptSalt, 0, firstPassBytes, 0, firstPassBytes, 20 ); |
||||
|
||||
// send the packet |
||||
packet = CreatePacket(null); |
||||
packet.Write( firstPassBytes, 0, 20 ); |
||||
SendPacket(packet); |
||||
} |
||||
*/ |
||||
|
||||
/// <summary> |
||||
/// Simple XOR scramble |
||||
/// </summary> |
||||
/// <param name="from">Source array</param> |
||||
/// <param name="fromIndex">Index inside source array</param> |
||||
/// <param name="to">Destination array</param> |
||||
/// <param name="toIndex">Index inside destination array</param> |
||||
/// <param name="password">Password used to xor the bits</param> |
||||
/// <param name="length">Number of bytes to scramble</param> |
||||
private static void XorScramble(byte[] from, int fromIndex, byte[] to, int toIndex, |
||||
byte[] password, int length) |
||||
{ |
||||
// make sure we were called properly |
||||
if (fromIndex < 0 || fromIndex >= from.Length) |
||||
throw new ArgumentException(Resources.IndexMustBeValid, "fromIndex"); |
||||
if ((fromIndex + length) > from.Length) |
||||
throw new ArgumentException(Resources.FromAndLengthTooBig, "fromIndex"); |
||||
if (from == null) |
||||
throw new ArgumentException(Resources.BufferCannotBeNull, "from"); |
||||
if (to == null) |
||||
throw new ArgumentException(Resources.BufferCannotBeNull, "to"); |
||||
if (toIndex < 0 || toIndex >= to.Length) |
||||
throw new ArgumentException(Resources.IndexMustBeValid, "toIndex"); |
||||
if ((toIndex + length) > to.Length) |
||||
throw new ArgumentException(Resources.IndexAndLengthTooBig, "toIndex"); |
||||
if (password == null || password.Length < length) |
||||
throw new ArgumentException(Resources.PasswordMustHaveLegalChars, "password"); |
||||
if (length < 0) |
||||
throw new ArgumentException(Resources.ParameterCannotBeNegative, "count"); |
||||
|
||||
// now perform the work |
||||
for (int i = 0; i < length; i++) |
||||
to[toIndex++] = (byte) (from[fromIndex++] ^ password[i]); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Generate a scrambled password for 4.1.0 using new passwords |
||||
/// </summary> |
||||
/// <param name="password">The password to scramble</param> |
||||
/// <param name="seedBytes">The seedbytes used to scramble</param> |
||||
/// <returns>Array of bytes containing the scrambled password</returns> |
||||
public static byte[] Get410Password(string password, byte[] seedBytes) |
||||
{ |
||||
SHA1Hash sha = new SHA1Hash(); |
||||
//SHA1 sha = new SHA1CryptoServiceProvider(); |
||||
|
||||
// clean it and then digest it |
||||
password = password.Replace(" ", "").Replace("\t", ""); |
||||
byte[] passBytes = Encoding.Default.GetBytes(password); |
||||
byte[] firstPass = sha.ComputeHash(passBytes); |
||||
|
||||
byte[] input = new byte[24]; |
||||
Array.Copy(seedBytes, 0, input, 0, 4); |
||||
Array.Copy(firstPass, 0, input, 4, 20); |
||||
byte[] secondPass = sha.ComputeHash(input); |
||||
|
||||
byte[] scrambledBuff = new byte[20]; |
||||
XorScramble(seedBytes, 4, scrambledBuff, 0, secondPass, 20); |
||||
|
||||
byte[] finalBuff = new byte[20]; |
||||
XorScramble(scrambledBuff, 0, finalBuff, 0, firstPass, 20); |
||||
|
||||
return finalBuff; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Generates a proper hash for old style 4.1.0 passwords. This would be used |
||||
/// if a 4.1.0 server contained old 16 byte hashes. |
||||
/// </summary> |
||||
/// <param name="password">The password to hash</param> |
||||
/// <param name="seedBytes">Seed bytes received from the server</param> |
||||
/// <returns>Byte array containing the password hash</returns> |
||||
public static byte[] GetOld410Password(string password, byte[] seedBytes) |
||||
{ |
||||
long[] passwordHash = Hash(password); |
||||
string passHex = String.Format(CultureInfo.InvariantCulture, |
||||
"{0,8:X}{1,8:X}", passwordHash[0], passwordHash[1]); |
||||
|
||||
int[] salt = getSaltFromPassword(passHex); |
||||
|
||||
// compute binary password |
||||
byte[] binaryPassword = new byte[20]; |
||||
int offset = 0; |
||||
for (int i = 0; i < 2; i++) |
||||
{ |
||||
int val = salt[i]; |
||||
|
||||
for (int t = 3; t >= 0; t--) |
||||
{ |
||||
binaryPassword[t + offset] = (byte) (val%256); |
||||
val >>= 8; /* Scroll 8 bits to get next part*/ |
||||
} |
||||
|
||||
offset += 4; |
||||
} |
||||
|
||||
//SHA1 sha = new SHA1CryptoServiceProvider(); |
||||
SHA1Hash sha = new SHA1Hash(); |
||||
byte[] temp = new byte[8]; |
||||
Buffer.BlockCopy(binaryPassword, 0, temp, 0, 8); |
||||
byte[] binaryHash = sha.ComputeHash(temp); |
||||
|
||||
byte[] scrambledBuff = new byte[20]; |
||||
XorScramble(seedBytes, 4, scrambledBuff, 0, binaryHash, 20); |
||||
|
||||
string scrambleString = Encoding.Default.GetString(scrambledBuff, 0, scrambledBuff.Length).Substring(0, 8); |
||||
|
||||
long[] hashPass = Hash(password); |
||||
long[] hashMessage = Hash(scrambleString); |
||||
|
||||
long max = 0x3FFFFFFFL; |
||||
byte[] to = new byte[20]; |
||||
int msgPos = 0; |
||||
int msgLength = scrambleString.Length; |
||||
int toPos = 0; |
||||
long seed1 = (hashPass[0] ^ hashMessage[0])%max; |
||||
long seed2 = (hashPass[1] ^ hashMessage[1])%max; |
||||
|
||||
while (msgPos++ < msgLength) |
||||
to[toPos++] = (byte) (Math.Floor(rand(ref seed1, ref seed2, max)*31) + 64); |
||||
|
||||
/* Make it harder to break */ |
||||
byte extra = (byte) (Math.Floor(rand(ref seed1, ref seed2, max)*31)); |
||||
|
||||
for (int i = 0; i < 8; i++) |
||||
to[i] ^= extra; |
||||
|
||||
return to; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a byte array containing the proper encryption of the |
||||
/// given password/seed according to the new 4.1.1 authentication scheme. |
||||
/// </summary> |
||||
/// <param name="password"></param> |
||||
/// <param name="seed"></param> |
||||
/// <returns></returns> |
||||
public static byte[] Get411Password(string password, string seed) |
||||
{ |
||||
// if we have no password, then we just return 1 zero byte |
||||
if (password.Length == 0) return new byte[1]; |
||||
|
||||
//SHA1 sha = new SHA1CryptoServiceProvider(); |
||||
SHA1Hash sha = new SHA1Hash(); |
||||
|
||||
byte[] firstHash = sha.ComputeHash(Encoding.Default.GetBytes(password)); |
||||
byte[] secondHash = sha.ComputeHash(firstHash); |
||||
byte[] seedBytes = Encoding.Default.GetBytes(seed); |
||||
|
||||
byte[] input = new byte[seedBytes.Length + secondHash.Length]; |
||||
Array.Copy(seedBytes, 0, input, 0, seedBytes.Length); |
||||
Array.Copy(secondHash, 0, input, seedBytes.Length, secondHash.Length); |
||||
byte[] thirdHash = sha.ComputeHash(input); |
||||
|
||||
byte[] finalHash = new byte[thirdHash.Length + 1]; |
||||
finalHash[0] = 0x14; |
||||
Array.Copy(thirdHash, 0, finalHash, 1, thirdHash.Length); |
||||
|
||||
for (int i = 1; i < finalHash.Length; i++) |
||||
finalHash[i] = (byte) (finalHash[i] ^ firstHash[i - 1]); |
||||
return finalHash; |
||||
} |
||||
|
||||
private static int[] getSaltFromPassword(String password) |
||||
{ |
||||
int[] result = new int[6]; |
||||
|
||||
if (password == null || password.Length == 0) |
||||
return result; |
||||
|
||||
int resultPos = 0; |
||||
int pos = 0; |
||||
|
||||
while (pos < password.Length) |
||||
{ |
||||
int val = 0; |
||||
|
||||
for (int i = 0; i < 8; i++) |
||||
val = (val << 4) + HexValue(password[pos++]); |
||||
|
||||
result[resultPos++] = val; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
private static int HexValue(char c) |
||||
{ |
||||
if (c >= 'A' && c <= 'Z') return (c - 'A') + 10; |
||||
if (c >= 'a' && c <= 'z') return (c - 'a') + 10; |
||||
return c - '0'; |
||||
} |
||||
|
||||
|
||||
private static double rand(ref long seed1, ref long seed2, long max) |
||||
{ |
||||
seed1 = (seed1*3) + seed2; |
||||
seed1 %= max; |
||||
seed2 = (seed1 + seed2 + 33)%max; |
||||
return (seed1/(double) max); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Encrypts a password using the MySql encryption scheme |
||||
/// </summary> |
||||
/// <param name="password">The password to encrypt</param> |
||||
/// <param name="seed">The encryption seed the server gave us</param> |
||||
/// <param name="new_ver">Indicates if we should use the old or new encryption scheme</param> |
||||
/// <returns></returns> |
||||
public static String EncryptPassword(String password, String seed, bool new_ver) |
||||
{ |
||||
long max = 0x3fffffff; |
||||
if (! new_ver) |
||||
max = 0x01FFFFFF; |
||||
if (password == null || password.Length == 0) |
||||
return password; |
||||
|
||||
long[] hash_seed = Hash(seed); |
||||
long[] hash_pass = Hash(password); |
||||
|
||||
long seed1 = (hash_seed[0] ^ hash_pass[0])%max; |
||||
long seed2 = (hash_seed[1] ^ hash_pass[1])%max; |
||||
if (! new_ver) |
||||
seed2 = seed1/2; |
||||
|
||||
char[] scrambled = new char[seed.Length]; |
||||
for (int x = 0; x < seed.Length; x++) |
||||
{ |
||||
double r = rand(ref seed1, ref seed2, max); |
||||
scrambled[x] = (char) (Math.Floor(r*31) + 64); |
||||
} |
||||
|
||||
if (new_ver) |
||||
{ |
||||
/* Make it harder to break */ |
||||
char extra = (char) Math.Floor(rand(ref seed1, ref seed2, max)*31); |
||||
for (int x = 0; x < scrambled.Length; x++) |
||||
scrambled[x] ^= extra; |
||||
} |
||||
|
||||
return new string(scrambled); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Hashes a password using the algorithm from Monty's code. |
||||
/// The first element in the return is the result of the "old" hash. |
||||
/// The second element is the rest of the "new" hash. |
||||
/// </summary> |
||||
/// <param name="P">Password to be hashed</param> |
||||
/// <returns>Two element array containing the hashed values</returns> |
||||
private static long[] Hash(String P) |
||||
{ |
||||
long val1 = 1345345333; |
||||
long val2 = 0x12345671; |
||||
long inc = 7; |
||||
|
||||
for (int i = 0; i < P.Length; i++) |
||||
{ |
||||
if (P[i] == ' ' || P[i] == '\t') continue; |
||||
long temp = (0xff & P[i]); |
||||
val1 ^= (((val1 & 63) + inc)*temp) + (val1 << 8); |
||||
val2 += (val2 << 8) ^ val1; |
||||
inc += temp; |
||||
} |
||||
|
||||
long[] hash = new long[2]; |
||||
hash[0] = val1 & 0x7fffffff; |
||||
hash[1] = val2 & 0x7fffffff; |
||||
return hash; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,513 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Globalization; |
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using MySql.Data.Types; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using System.Diagnostics; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for BaseDriver. |
||||
/// </summary> |
||||
internal class Driver : IDisposable |
||||
{ |
||||
protected Encoding encoding; |
||||
protected MySqlConnectionStringBuilder connectionString; |
||||
protected ClientFlags serverCaps; |
||||
protected bool isOpen; |
||||
protected DateTime creationTime; |
||||
protected string serverCharSet; |
||||
protected int serverCharSetIndex; |
||||
protected Hashtable serverProps; |
||||
protected Hashtable charSets; |
||||
protected long maxPacketSize; |
||||
private DateTime idleSince; |
||||
|
||||
#if !CF |
||||
protected MySqlPromotableTransaction currentTransaction; |
||||
protected bool inActiveUse; |
||||
#endif |
||||
protected MySqlPool pool; |
||||
private bool firstResult; |
||||
protected IDriver handler; |
||||
internal MySqlDataReader reader; |
||||
|
||||
/// <summary> |
||||
/// For pooled connections, time when the driver was |
||||
/// put into idle queue |
||||
/// </summary> |
||||
public DateTime IdleSince |
||||
{ |
||||
get { return idleSince; } |
||||
set { idleSince = value; } |
||||
} |
||||
|
||||
public Driver(MySqlConnectionStringBuilder settings) |
||||
{ |
||||
encoding = Encoding.GetEncoding(1252); |
||||
if (encoding == null) |
||||
throw new MySqlException(Resources.DefaultEncodingNotFound); |
||||
connectionString = settings; |
||||
serverCharSet = "latin1"; |
||||
serverCharSetIndex = -1; |
||||
maxPacketSize = 1024; |
||||
handler = new NativeDriver(this); |
||||
} |
||||
|
||||
~Driver() |
||||
{ |
||||
Close(); |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public int ThreadID |
||||
{ |
||||
get { return handler.ThreadId; } |
||||
} |
||||
|
||||
public DBVersion Version |
||||
{ |
||||
get { return handler.Version; } |
||||
} |
||||
|
||||
public MySqlConnectionStringBuilder Settings |
||||
{ |
||||
get { return connectionString; } |
||||
set { connectionString = value; } |
||||
} |
||||
|
||||
public Encoding Encoding |
||||
{ |
||||
get { return encoding; } |
||||
set { encoding = value; } |
||||
} |
||||
|
||||
#if !CF |
||||
public MySqlPromotableTransaction CurrentTransaction |
||||
{ |
||||
get { return currentTransaction; } |
||||
set { currentTransaction = value; } |
||||
} |
||||
|
||||
public bool IsInActiveUse |
||||
{ |
||||
get { return inActiveUse; } |
||||
set { inActiveUse = value; } |
||||
} |
||||
#endif |
||||
public bool IsOpen |
||||
{ |
||||
get { return isOpen; } |
||||
} |
||||
|
||||
public MySqlPool Pool |
||||
{ |
||||
get { return pool; } |
||||
set { pool = value; } |
||||
} |
||||
|
||||
public long MaxPacketSize |
||||
{ |
||||
get { return maxPacketSize; } |
||||
} |
||||
|
||||
internal int ConnectionCharSetIndex |
||||
{ |
||||
get { return serverCharSetIndex; } |
||||
set { serverCharSetIndex = value; } |
||||
} |
||||
|
||||
internal Hashtable CharacterSets |
||||
{ |
||||
get { return charSets; } |
||||
} |
||||
|
||||
public bool SupportsOutputParameters |
||||
{ |
||||
get { return Version.isAtLeast(6,0,8); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns true if this connection can handle batch SQL natively |
||||
/// This means MySQL 4.1.1 or later. |
||||
/// </summary> |
||||
public bool SupportsBatch |
||||
{ |
||||
get |
||||
{ |
||||
if ((handler.Flags & ClientFlags.MULTI_STATEMENTS) != 0) |
||||
{ |
||||
if (Version.isAtLeast(4, 1, 0) && !Version.isAtLeast(4, 1, 10)) |
||||
{ |
||||
object qtType = serverProps["query_cache_type"]; |
||||
object qtSize = serverProps["query_cache_size"]; |
||||
if (qtType != null && qtType.Equals("ON") && |
||||
(qtSize != null && !qtSize.Equals("0"))) |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public string Property(string key) |
||||
{ |
||||
return (string) serverProps[key]; |
||||
} |
||||
|
||||
public bool ConnectionLifetimeExpired() |
||||
{ |
||||
TimeSpan ts = DateTime.Now.Subtract(creationTime); |
||||
if (Settings.ConnectionLifeTime != 0 && |
||||
ts.TotalSeconds > Settings.ConnectionLifeTime) |
||||
return true; |
||||
return false; |
||||
} |
||||
|
||||
public static Driver Create(MySqlConnectionStringBuilder settings) |
||||
{ |
||||
Driver d = null; |
||||
|
||||
#if !CF |
||||
if (settings.Logging || settings.UseUsageAdvisor) |
||||
d = new TracingDriver(settings); |
||||
else |
||||
#endif |
||||
d = new Driver(settings); |
||||
d.Open(); |
||||
return d; |
||||
} |
||||
|
||||
public bool HasStatus(ServerStatusFlags flag) |
||||
{ |
||||
return (handler.ServerStatus & flag) != 0; |
||||
} |
||||
|
||||
public virtual void Open() |
||||
{ |
||||
creationTime = DateTime.Now; |
||||
handler.Open(); |
||||
isOpen = true; |
||||
} |
||||
|
||||
public virtual void Close() |
||||
{ |
||||
Dispose(); |
||||
} |
||||
|
||||
public virtual void Configure(MySqlConnection connection) |
||||
{ |
||||
bool firstConfigure = false; |
||||
// if we have not already configured our server variables |
||||
// then do so now |
||||
if (serverProps == null) |
||||
{ |
||||
firstConfigure = true; |
||||
// load server properties |
||||
serverProps = new Hashtable(); |
||||
MySqlCommand cmd = new MySqlCommand("SHOW VARIABLES", connection); |
||||
|
||||
using (MySqlDataReader reader = cmd.ExecuteReader()) |
||||
{ |
||||
try |
||||
{ |
||||
while (reader.Read()) |
||||
{ |
||||
string key = reader.GetString(0); |
||||
string value = reader.GetString(1); |
||||
serverProps[key] = value; |
||||
} |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
MySqlTrace.LogError(ThreadID, ex.Message); |
||||
throw; |
||||
} |
||||
} |
||||
|
||||
if (serverProps.Contains("max_allowed_packet")) |
||||
maxPacketSize = Convert.ToInt64(serverProps["max_allowed_packet"]); |
||||
|
||||
LoadCharacterSets(connection); |
||||
} |
||||
|
||||
#if AUTHENTICATED |
||||
string licenseType = serverProps["license"]; |
||||
if (licenseType == null || licenseType.Length == 0 || |
||||
licenseType != "commercial") |
||||
throw new MySqlException( "This client library licensed only for use with commercially-licensed MySQL servers." ); |
||||
#endif |
||||
// if the user has indicated that we are not to reset |
||||
// the connection and this is not our first time through, |
||||
// then we are done. |
||||
if (!Settings.ConnectionReset && !firstConfigure) return; |
||||
|
||||
string charSet = connectionString.CharacterSet; |
||||
if (charSet == null || charSet.Length == 0) |
||||
{ |
||||
if (serverCharSetIndex >= 0) |
||||
charSet = (string) charSets[serverCharSetIndex]; |
||||
else |
||||
charSet = serverCharSet; |
||||
} |
||||
|
||||
// now tell the server which character set we will send queries in and which charset we |
||||
// want results in |
||||
MySqlCommand charSetCmd = new MySqlCommand("SET character_set_results=NULL", |
||||
connection); |
||||
object clientCharSet = serverProps["character_set_client"]; |
||||
object connCharSet = serverProps["character_set_connection"]; |
||||
if ((clientCharSet != null && clientCharSet.ToString() != charSet) || |
||||
(connCharSet != null && connCharSet.ToString() != charSet)) |
||||
{ |
||||
MySqlCommand setNamesCmd = new MySqlCommand("SET NAMES " + charSet, connection); |
||||
setNamesCmd.ExecuteNonQuery(); |
||||
} |
||||
charSetCmd.ExecuteNonQuery(); |
||||
|
||||
if (charSet != null) |
||||
Encoding = CharSetMap.GetEncoding(Version, charSet); |
||||
else |
||||
Encoding = CharSetMap.GetEncoding(Version, "latin1"); |
||||
|
||||
handler.Configure(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Loads all the current character set names and ids for this server |
||||
/// into the charSets hashtable |
||||
/// </summary> |
||||
private void LoadCharacterSets(MySqlConnection connection) |
||||
{ |
||||
MySqlCommand cmd = new MySqlCommand("SHOW COLLATION", connection); |
||||
|
||||
// now we load all the currently active collations |
||||
try |
||||
{ |
||||
using (MySqlDataReader reader = cmd.ExecuteReader()) |
||||
{ |
||||
charSets = new Hashtable(); |
||||
while (reader.Read()) |
||||
{ |
||||
charSets[Convert.ToInt32(reader["id"], NumberFormatInfo.InvariantInfo)] = |
||||
reader.GetString(reader.GetOrdinal("charset")); |
||||
} |
||||
} |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
MySqlTrace.LogError(ThreadID, ex.Message); |
||||
throw; |
||||
} |
||||
} |
||||
|
||||
public virtual List<MySqlError> ReportWarnings(MySqlConnection connection) |
||||
{ |
||||
List<MySqlError> warnings = new List<MySqlError>(); |
||||
|
||||
MySqlCommand cmd = new MySqlCommand("SHOW WARNINGS", connection); |
||||
using (MySqlDataReader reader = cmd.ExecuteReader()) |
||||
{ |
||||
while (reader.Read()) |
||||
{ |
||||
warnings.Add(new MySqlError(reader.GetString(0), |
||||
reader.GetInt32(1), reader.GetString(2))); |
||||
} |
||||
} |
||||
|
||||
MySqlInfoMessageEventArgs args = new MySqlInfoMessageEventArgs(); |
||||
args.errors = warnings.ToArray(); |
||||
if (connection != null) |
||||
connection.OnInfoMessage(args); |
||||
return warnings; |
||||
} |
||||
|
||||
public virtual void SendQuery(MySqlPacket p) |
||||
{ |
||||
handler.SendQuery(p); |
||||
firstResult = true; |
||||
} |
||||
|
||||
public virtual ResultSet NextResult(int statementId) |
||||
{ |
||||
if (!firstResult && !HasStatus(ServerStatusFlags.AnotherQuery | ServerStatusFlags.MoreResults)) |
||||
return null; |
||||
firstResult = false; |
||||
|
||||
int affectedRows = -1, insertedId = -1, warnings = 0; |
||||
int fieldCount = GetResult(statementId, ref affectedRows, ref insertedId); |
||||
if (fieldCount == -1) |
||||
return null; |
||||
if (fieldCount > 0) |
||||
return new ResultSet(this, statementId, fieldCount); |
||||
else |
||||
return new ResultSet(affectedRows, insertedId); |
||||
} |
||||
|
||||
protected virtual int GetResult(int statementId, ref int affectedRows, ref int insertedId) |
||||
{ |
||||
return handler.GetResult(ref affectedRows, ref insertedId); |
||||
} |
||||
|
||||
public virtual bool FetchDataRow(int statementId, int columns) |
||||
{ |
||||
return handler.FetchDataRow(statementId, columns); |
||||
} |
||||
|
||||
public virtual bool SkipDataRow() |
||||
{ |
||||
return FetchDataRow(-1, 0); |
||||
} |
||||
|
||||
public virtual void ExecuteDirect(string sql) |
||||
{ |
||||
MySqlPacket p = new MySqlPacket(Encoding); |
||||
p.WriteString(sql); |
||||
SendQuery(p); |
||||
NextResult(0); |
||||
} |
||||
|
||||
public MySqlField[] GetColumns(int count) |
||||
{ |
||||
MySqlField[] fields = new MySqlField[count]; |
||||
for (int i = 0; i < count; i++) |
||||
fields[i] = new MySqlField(this); |
||||
handler.GetColumnsData(fields); |
||||
|
||||
return fields; |
||||
} |
||||
|
||||
public virtual int PrepareStatement(string sql, ref MySqlField[] parameters) |
||||
{ |
||||
return handler.PrepareStatement(sql, ref parameters); |
||||
} |
||||
|
||||
public IMySqlValue ReadColumnValue(int index, MySqlField field, IMySqlValue value) |
||||
{ |
||||
return handler.ReadColumnValue(index, field, value); |
||||
} |
||||
|
||||
public void SkipColumnValue(IMySqlValue valObject) |
||||
{ |
||||
handler.SkipColumnValue(valObject); |
||||
} |
||||
|
||||
public void ResetTimeout(int timeoutMilliseconds) |
||||
{ |
||||
handler.ResetTimeout(timeoutMilliseconds); |
||||
} |
||||
|
||||
public bool Ping() |
||||
{ |
||||
return handler.Ping(); |
||||
} |
||||
|
||||
public virtual void SetDatabase(string dbName) |
||||
{ |
||||
handler.SetDatabase(dbName); |
||||
} |
||||
|
||||
public virtual void ExecuteStatement(MySqlPacket packetToExecute) |
||||
{ |
||||
handler.ExecuteStatement(packetToExecute); |
||||
} |
||||
|
||||
|
||||
public virtual void CloseStatement(int id) |
||||
{ |
||||
handler.CloseStatement(id); |
||||
} |
||||
|
||||
public virtual void Reset() |
||||
{ |
||||
handler.Reset(); |
||||
} |
||||
|
||||
public virtual void CloseQuery(MySqlConnection connection, int statementId) |
||||
{ |
||||
if (handler.WarningCount > 0) |
||||
ReportWarnings(connection); |
||||
} |
||||
|
||||
#region IDisposable Members |
||||
|
||||
protected virtual void Dispose(bool disposing) |
||||
{ |
||||
ResetTimeout(1000); |
||||
if (disposing) |
||||
handler.Close(isOpen); |
||||
// if we are pooling, then release ourselves |
||||
if (connectionString.Pooling) |
||||
MySqlPoolManager.RemoveConnection(this); |
||||
|
||||
isOpen = false; |
||||
} |
||||
|
||||
public void Dispose() |
||||
{ |
||||
Dispose(true); |
||||
GC.SuppressFinalize(this); |
||||
} |
||||
|
||||
internal bool isExecutingBuggyQuery; |
||||
internal bool IsExecutingBuggyQuery |
||||
{ |
||||
get { return isExecutingBuggyQuery; } |
||||
set { isExecutingBuggyQuery = value; } |
||||
} |
||||
#endregion |
||||
} |
||||
|
||||
internal interface IDriver |
||||
{ |
||||
int ThreadId { get; } |
||||
DBVersion Version { get; } |
||||
ServerStatusFlags ServerStatus { get; } |
||||
ClientFlags Flags { get; } |
||||
void Configure(); |
||||
void Open(); |
||||
void SendQuery(MySqlPacket packet); |
||||
void Close(bool isOpen); |
||||
bool Ping(); |
||||
int GetResult(ref int affectedRows, ref int insertedId); |
||||
bool FetchDataRow(int statementId, int columns); |
||||
int PrepareStatement(string sql, ref MySqlField[] parameters); |
||||
void ExecuteStatement(MySqlPacket packet); |
||||
void CloseStatement(int statementId); |
||||
void SetDatabase(string dbName); |
||||
void Reset(); |
||||
IMySqlValue ReadColumnValue(int index, MySqlField field, IMySqlValue valObject); |
||||
void SkipColumnValue(IMySqlValue valueObject); |
||||
void GetColumnsData(MySqlField[] columns); |
||||
void ResetTimeout(int timeout); |
||||
int WarningCount { get; } |
||||
} |
||||
} |
@ -0,0 +1,94 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data.Common; |
||||
#if !CF |
||||
using System.Runtime.Serialization; |
||||
#endif |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// The exception that is thrown when MySQL returns an error. This class cannot be inherited. |
||||
/// </summary> |
||||
/// <include file='docs/MySqlException.xml' path='MyDocs/MyMembers[@name="Class"]/*'/> |
||||
#if !CF |
||||
[Serializable] |
||||
#endif |
||||
public sealed class MySqlException : DbException |
||||
{ |
||||
private int errorCode; |
||||
private bool isFatal; |
||||
|
||||
internal MySqlException() |
||||
{ |
||||
} |
||||
|
||||
internal MySqlException(string msg) : base(msg) |
||||
{ |
||||
} |
||||
|
||||
internal MySqlException(string msg, Exception ex) : base(msg, ex) |
||||
{ |
||||
} |
||||
|
||||
internal MySqlException(string msg, bool isFatal, Exception inner) : base (msg, inner) |
||||
{ |
||||
this.isFatal = isFatal; |
||||
} |
||||
|
||||
internal MySqlException(string msg, int errno, Exception inner) |
||||
: this(msg, inner) |
||||
{ |
||||
errorCode = errno; |
||||
#if !CF |
||||
Data.Add("Server Error Code", errno); |
||||
#endif |
||||
} |
||||
|
||||
internal MySqlException(string msg, int errno) |
||||
: this(msg, errno, null) |
||||
{ |
||||
} |
||||
|
||||
#if !CF |
||||
private MySqlException(SerializationInfo info, StreamingContext context) : base(info, context) |
||||
{ |
||||
} |
||||
#endif |
||||
|
||||
/// <summary> |
||||
/// Gets a number that identifies the type of error. |
||||
/// </summary> |
||||
public int Number |
||||
{ |
||||
get { return errorCode; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// True if this exception was fatal and cause the closing of the connection, false otherwise. |
||||
/// </summary> |
||||
internal bool IsFatal |
||||
{ |
||||
get { return isFatal; } |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,417 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using MySql.Data.Types; |
||||
using System.Globalization; |
||||
using System.Text.RegularExpressions; |
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
internal enum ColumnFlags : int |
||||
{ |
||||
NOT_NULL = 1, |
||||
PRIMARY_KEY = 2, |
||||
UNIQUE_KEY = 4, |
||||
MULTIPLE_KEY = 8, |
||||
BLOB = 16, |
||||
UNSIGNED = 32, |
||||
ZERO_FILL = 64, |
||||
BINARY = 128, |
||||
ENUM = 256, |
||||
AUTO_INCREMENT = 512, |
||||
TIMESTAMP = 1024, |
||||
SET = 2048, |
||||
NUMBER = 32768 |
||||
} ; |
||||
|
||||
/// <summary> |
||||
/// Summary description for Field. |
||||
/// </summary> |
||||
internal class MySqlField |
||||
{ |
||||
#region Fields |
||||
|
||||
// public fields |
||||
public string CatalogName; |
||||
public int ColumnLength; |
||||
public string ColumnName; |
||||
public string OriginalColumnName; |
||||
public string TableName; |
||||
public string RealTableName; |
||||
public string DatabaseName; |
||||
public Encoding Encoding; |
||||
public int maxLength; |
||||
|
||||
// protected fields |
||||
protected ColumnFlags colFlags; |
||||
protected int charSetIndex; |
||||
protected byte precision; |
||||
protected byte scale; |
||||
protected MySqlDbType mySqlDbType; |
||||
protected DBVersion connVersion; |
||||
protected Driver driver; |
||||
protected bool binaryOk; |
||||
protected List<Type> typeConversions = new List<Type>(); |
||||
|
||||
#endregion |
||||
|
||||
public MySqlField(Driver driver) |
||||
{ |
||||
this.driver = driver; |
||||
connVersion = driver.Version; |
||||
maxLength = 1; |
||||
binaryOk = true; |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public int CharacterSetIndex |
||||
{ |
||||
get { return charSetIndex; } |
||||
set { charSetIndex = value; SetFieldEncoding(); } |
||||
} |
||||
|
||||
public MySqlDbType Type |
||||
{ |
||||
get { return mySqlDbType; } |
||||
} |
||||
|
||||
public byte Precision |
||||
{ |
||||
get { return precision; } |
||||
set { precision = value; } |
||||
} |
||||
|
||||
public byte Scale |
||||
{ |
||||
get { return scale; } |
||||
set { scale = value; } |
||||
} |
||||
|
||||
public int MaxLength |
||||
{ |
||||
get { return maxLength; } |
||||
set { maxLength = value; } |
||||
} |
||||
|
||||
public ColumnFlags Flags |
||||
{ |
||||
get { return colFlags; } |
||||
} |
||||
|
||||
public bool IsAutoIncrement |
||||
{ |
||||
get { return (colFlags & ColumnFlags.AUTO_INCREMENT) > 0; } |
||||
} |
||||
|
||||
public bool IsNumeric |
||||
{ |
||||
get { return (colFlags & ColumnFlags.NUMBER) > 0; } |
||||
} |
||||
|
||||
public bool AllowsNull |
||||
{ |
||||
get { return (colFlags & ColumnFlags.NOT_NULL) == 0; } |
||||
} |
||||
|
||||
public bool IsUnique |
||||
{ |
||||
get { return (colFlags & ColumnFlags.UNIQUE_KEY) > 0; } |
||||
} |
||||
|
||||
public bool IsPrimaryKey |
||||
{ |
||||
get { return (colFlags & ColumnFlags.PRIMARY_KEY) > 0; } |
||||
} |
||||
|
||||
public bool IsBlob |
||||
{ |
||||
get |
||||
{ |
||||
return (mySqlDbType >= MySqlDbType.TinyBlob && |
||||
mySqlDbType <= MySqlDbType.Blob) || |
||||
(mySqlDbType >= MySqlDbType.TinyText && |
||||
mySqlDbType <= MySqlDbType.Text) || |
||||
(colFlags & ColumnFlags.BLOB) > 0; |
||||
} |
||||
} |
||||
|
||||
public bool IsBinary |
||||
{ |
||||
get |
||||
{ |
||||
return binaryOk && (CharacterSetIndex == 63); |
||||
} |
||||
} |
||||
|
||||
public bool IsUnsigned |
||||
{ |
||||
get { return (colFlags & ColumnFlags.UNSIGNED) > 0; } |
||||
} |
||||
|
||||
public bool IsTextField |
||||
{ |
||||
get |
||||
{ |
||||
return Type == MySqlDbType.VarString || Type == MySqlDbType.VarChar || |
||||
(IsBlob && !IsBinary); |
||||
} |
||||
} |
||||
|
||||
public int CharacterLength |
||||
{ |
||||
get { return ColumnLength / MaxLength; } |
||||
} |
||||
|
||||
public List<Type> TypeConversions |
||||
{ |
||||
get { return typeConversions; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public void SetTypeAndFlags(MySqlDbType type, ColumnFlags flags) |
||||
{ |
||||
colFlags = flags; |
||||
mySqlDbType = type; |
||||
|
||||
if (String.IsNullOrEmpty(TableName) && String.IsNullOrEmpty(RealTableName) && |
||||
driver.Settings.FunctionsReturnString) |
||||
{ |
||||
mySqlDbType = MySqlDbType.VarString; |
||||
// we are treating a binary as string so we have to choose some |
||||
// charset index. Connection seems logical. |
||||
CharacterSetIndex = driver.ConnectionCharSetIndex; |
||||
binaryOk = false; |
||||
} |
||||
|
||||
// if our type is an unsigned number, then we need |
||||
// to bump it up into our unsigned types |
||||
// we're trusting that the server is not going to set the UNSIGNED |
||||
// flag unless we are a number |
||||
if (IsUnsigned) |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case MySqlDbType.Byte: |
||||
mySqlDbType = MySqlDbType.UByte; |
||||
return; |
||||
case MySqlDbType.Int16: |
||||
mySqlDbType = MySqlDbType.UInt16; |
||||
return; |
||||
case MySqlDbType.Int24: |
||||
mySqlDbType = MySqlDbType.UInt24; |
||||
return; |
||||
case MySqlDbType.Int32: |
||||
mySqlDbType = MySqlDbType.UInt32; |
||||
return; |
||||
case MySqlDbType.Int64: |
||||
mySqlDbType = MySqlDbType.UInt64; |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (IsBlob) |
||||
{ |
||||
// handle blob to UTF8 conversion if requested. This is only activated |
||||
// on binary blobs |
||||
if (IsBinary && driver.Settings.TreatBlobsAsUTF8) |
||||
{ |
||||
bool convertBlob = false; |
||||
Regex includeRegex = driver.Settings.GetBlobAsUTF8IncludeRegex(); |
||||
Regex excludeRegex = driver.Settings.GetBlobAsUTF8ExcludeRegex(); |
||||
if (includeRegex != null && includeRegex.IsMatch(ColumnName)) |
||||
convertBlob = true; |
||||
else if (includeRegex == null && excludeRegex != null && |
||||
!excludeRegex.IsMatch(ColumnName)) |
||||
convertBlob = true; |
||||
|
||||
if (convertBlob) |
||||
{ |
||||
binaryOk = false; |
||||
Encoding = System.Text.Encoding.GetEncoding("UTF-8"); |
||||
charSetIndex = -1; // lets driver know we are in charge of encoding |
||||
maxLength = 4; |
||||
} |
||||
} |
||||
|
||||
if (!IsBinary) |
||||
{ |
||||
if (type == MySqlDbType.TinyBlob) |
||||
mySqlDbType = MySqlDbType.TinyText; |
||||
else if (type == MySqlDbType.MediumBlob) |
||||
mySqlDbType = MySqlDbType.MediumText; |
||||
else if (type == MySqlDbType.Blob) |
||||
mySqlDbType = MySqlDbType.Text; |
||||
else if (type == MySqlDbType.LongBlob) |
||||
mySqlDbType = MySqlDbType.LongText; |
||||
} |
||||
} |
||||
|
||||
// now determine if we really should be binary |
||||
if (driver.Settings.RespectBinaryFlags) |
||||
CheckForExceptions(); |
||||
|
||||
if (Type == MySqlDbType.String && CharacterLength == 36 && !driver.Settings.OldGuids) |
||||
mySqlDbType = MySqlDbType.Guid; |
||||
|
||||
if (!IsBinary) return; |
||||
|
||||
if (driver.Settings.RespectBinaryFlags) |
||||
{ |
||||
if (type == MySqlDbType.String) |
||||
mySqlDbType = MySqlDbType.Binary; |
||||
else if (type == MySqlDbType.VarChar || |
||||
type == MySqlDbType.VarString) |
||||
mySqlDbType = MySqlDbType.VarBinary; |
||||
} |
||||
|
||||
if (CharacterSetIndex == 63) |
||||
CharacterSetIndex = driver.ConnectionCharSetIndex; |
||||
|
||||
if (Type == MySqlDbType.Binary && ColumnLength == 16 && driver.Settings.OldGuids) |
||||
mySqlDbType = MySqlDbType.Guid; |
||||
} |
||||
|
||||
public void AddTypeConversion(Type t) |
||||
{ |
||||
if (TypeConversions.Contains(t)) return; |
||||
TypeConversions.Add(t); |
||||
} |
||||
|
||||
private void CheckForExceptions() |
||||
{ |
||||
string colName = String.Empty; |
||||
if (OriginalColumnName != null) |
||||
colName = OriginalColumnName.ToUpper(CultureInfo.InvariantCulture); |
||||
if (colName.StartsWith("CHAR(")) |
||||
binaryOk = false; |
||||
else if (driver.IsExecutingBuggyQuery) |
||||
binaryOk = false; |
||||
} |
||||
|
||||
public IMySqlValue GetValueObject() |
||||
{ |
||||
IMySqlValue v = GetIMySqlValue(Type); |
||||
if (v is MySqlByte && ColumnLength == 1 && driver.Settings.TreatTinyAsBoolean) |
||||
{ |
||||
MySqlByte b = (MySqlByte)v; |
||||
b.TreatAsBoolean = true; |
||||
v = b; |
||||
} |
||||
else if (v is MySqlGuid) |
||||
{ |
||||
MySqlGuid g = (MySqlGuid)v; |
||||
g.OldGuids = driver.Settings.OldGuids; |
||||
v = g; |
||||
} |
||||
return v; |
||||
} |
||||
|
||||
public static IMySqlValue GetIMySqlValue(MySqlDbType type) |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case MySqlDbType.Byte: |
||||
return new MySqlByte(); |
||||
case MySqlDbType.UByte: |
||||
return new MySqlUByte(); |
||||
case MySqlDbType.Int16: |
||||
return new MySqlInt16(); |
||||
case MySqlDbType.UInt16: |
||||
return new MySqlUInt16(); |
||||
case MySqlDbType.Int24: |
||||
case MySqlDbType.Int32: |
||||
case MySqlDbType.Year: |
||||
return new MySqlInt32(type, true); |
||||
case MySqlDbType.UInt24: |
||||
case MySqlDbType.UInt32: |
||||
return new MySqlUInt32(type, true); |
||||
case MySqlDbType.Bit: |
||||
return new MySqlBit(); |
||||
case MySqlDbType.Int64: |
||||
return new MySqlInt64(); |
||||
case MySqlDbType.UInt64: |
||||
return new MySqlUInt64(); |
||||
case MySqlDbType.Time: |
||||
return new MySqlTimeSpan(); |
||||
case MySqlDbType.Date: |
||||
case MySqlDbType.DateTime: |
||||
case MySqlDbType.Newdate: |
||||
case MySqlDbType.Timestamp: |
||||
return new MySqlDateTime(type, true); |
||||
case MySqlDbType.Decimal: |
||||
case MySqlDbType.NewDecimal: |
||||
return new MySqlDecimal(); |
||||
case MySqlDbType.Float: |
||||
return new MySqlSingle(); |
||||
case MySqlDbType.Double: |
||||
return new MySqlDouble(); |
||||
case MySqlDbType.Set: |
||||
case MySqlDbType.Enum: |
||||
case MySqlDbType.String: |
||||
case MySqlDbType.VarString: |
||||
case MySqlDbType.VarChar: |
||||
case MySqlDbType.Text: |
||||
case MySqlDbType.TinyText: |
||||
case MySqlDbType.MediumText: |
||||
case MySqlDbType.LongText: |
||||
case (MySqlDbType) Field_Type.NULL: |
||||
return new MySqlString(type, true); |
||||
case MySqlDbType.Geometry: |
||||
case MySqlDbType.Blob: |
||||
case MySqlDbType.MediumBlob: |
||||
case MySqlDbType.LongBlob: |
||||
case MySqlDbType.TinyBlob: |
||||
case MySqlDbType.Binary: |
||||
case MySqlDbType.VarBinary: |
||||
return new MySqlBinary(type, true); |
||||
case MySqlDbType.Guid: |
||||
return new MySqlGuid(); |
||||
default: |
||||
throw new MySqlException("Unknown data type"); |
||||
} |
||||
} |
||||
|
||||
private void SetFieldEncoding() |
||||
{ |
||||
Hashtable charSets = driver.CharacterSets; |
||||
DBVersion version = driver.Version; |
||||
|
||||
if (charSets == null || CharacterSetIndex == -1) return; |
||||
if (charSets[CharacterSetIndex] == null) return; |
||||
|
||||
CharacterSet cs = CharSetMap.GetCharacterSet(version, (string)charSets[CharacterSetIndex]); |
||||
// starting with 6.0.4 utf8 has a maxlen of 4 instead of 3. The old |
||||
// 3 byte utf8 is utf8mb3 |
||||
if (cs.name.ToLower(System.Globalization.CultureInfo.InvariantCulture) == "utf-8" && |
||||
version.Major >= 6) |
||||
MaxLength = 4; |
||||
else |
||||
MaxLength = cs.byteCount; |
||||
Encoding = CharSetMap.GetEncoding(version, (string)charSets[CharacterSetIndex]); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,694 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using System.Globalization; |
||||
using System.Diagnostics; |
||||
using System.Data.SqlTypes; |
||||
using MySql.Data.Types; |
||||
using System.Collections; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
internal class ISSchemaProvider : SchemaProvider |
||||
{ |
||||
public ISSchemaProvider(MySqlConnection connection) : base(connection) |
||||
{ |
||||
} |
||||
|
||||
protected override DataTable GetCollections() |
||||
{ |
||||
DataTable dt = base.GetCollections(); |
||||
|
||||
object[][] collections = new object[][] |
||||
{ |
||||
new object[] {"Views", 2, 3}, |
||||
new object[] {"ViewColumns", 3, 4}, |
||||
new object[] {"Procedure Parameters", 5, 1}, |
||||
new object[] {"Procedures", 4, 3}, |
||||
new object[] {"Triggers", 2, 4} |
||||
}; |
||||
|
||||
FillTable(dt, collections); |
||||
return dt; |
||||
} |
||||
|
||||
protected override DataTable GetRestrictions() |
||||
{ |
||||
DataTable dt = base.GetRestrictions(); |
||||
|
||||
object[][] restrictions = new object[][] |
||||
{ |
||||
new object[] {"Procedure Parameters", "Database", "", 0}, |
||||
new object[] {"Procedure Parameters", "Schema", "", 1}, |
||||
new object[] {"Procedure Parameters", "Name", "", 2}, |
||||
new object[] {"Procedure Parameters", "Type", "", 3}, |
||||
new object[] {"Procedure Parameters", "Parameter", "", 4}, |
||||
new object[] {"Procedures", "Database", "", 0}, |
||||
new object[] {"Procedures", "Schema", "", 1}, |
||||
new object[] {"Procedures", "Name", "", 2}, |
||||
new object[] {"Procedures", "Type", "", 3}, |
||||
new object[] {"Views", "Database", "", 0}, |
||||
new object[] {"Views", "Schema", "", 1}, |
||||
new object[] {"Views", "Table", "", 2}, |
||||
new object[] {"ViewColumns", "Database", "", 0}, |
||||
new object[] {"ViewColumns", "Schema", "", 1}, |
||||
new object[] {"ViewColumns", "Table", "", 2}, |
||||
new object[] {"ViewColumns", "Column", "", 3}, |
||||
new object[] {"Triggers", "Database", "", 0}, |
||||
new object[] {"Triggers", "Schema", "", 1}, |
||||
new object[] {"Triggers", "Name", "", 2}, |
||||
new object[] {"Triggers", "EventObjectTable", "", 3}, |
||||
}; |
||||
FillTable(dt, restrictions); |
||||
return dt; |
||||
} |
||||
|
||||
public override DataTable GetDatabases(string[] restrictions) |
||||
{ |
||||
string[] keys = new string[1]; |
||||
keys[0] = "SCHEMA_NAME"; |
||||
DataTable dt = Query("SCHEMATA", "", keys, restrictions); |
||||
dt.Columns[1].ColumnName = "database_name"; |
||||
dt.TableName = "Databases"; |
||||
return dt; |
||||
} |
||||
|
||||
public override DataTable GetTables(string[] restrictions) |
||||
{ |
||||
string[] keys = new string[4]; |
||||
keys[0] = "TABLE_CATALOG"; |
||||
keys[1] = "TABLE_SCHEMA"; |
||||
keys[2] = "TABLE_NAME"; |
||||
keys[3] = "TABLE_TYPE"; |
||||
DataTable dt = Query("TABLES", "TABLE_TYPE != 'VIEW'", keys, restrictions); |
||||
dt.TableName = "Tables"; |
||||
return dt; |
||||
} |
||||
|
||||
public override DataTable GetColumns(string[] restrictions) |
||||
{ |
||||
string[] keys = new string[4]; |
||||
keys[0] = "TABLE_CATALOG"; |
||||
keys[1] = "TABLE_SCHEMA"; |
||||
keys[2] = "TABLE_NAME"; |
||||
keys[3] = "COLUMN_NAME"; |
||||
DataTable dt = Query("COLUMNS", null, keys, restrictions); |
||||
dt.Columns.Remove("CHARACTER_OCTET_LENGTH"); |
||||
dt.TableName = "Columns"; |
||||
return dt; |
||||
} |
||||
|
||||
private DataTable GetViews(string[] restrictions) |
||||
{ |
||||
string[] keys = new string[3]; |
||||
keys[0] = "TABLE_CATALOG"; |
||||
keys[1] = "TABLE_SCHEMA"; |
||||
keys[2] = "TABLE_NAME"; |
||||
DataTable dt = Query("VIEWS", null, keys, restrictions); |
||||
dt.TableName = "Views"; |
||||
return dt; |
||||
} |
||||
|
||||
private DataTable GetViewColumns(string[] restrictions) |
||||
{ |
||||
StringBuilder where = new StringBuilder(); |
||||
StringBuilder sql = new StringBuilder( |
||||
"SELECT C.* FROM information_schema.columns C"); |
||||
sql.Append(" JOIN information_schema.views V "); |
||||
sql.Append("ON C.table_schema=V.table_schema AND C.table_name=V.table_name "); |
||||
if (restrictions != null && restrictions.Length >= 2 && |
||||
restrictions[1] != null) |
||||
where.AppendFormat(CultureInfo.InvariantCulture, "C.table_schema='{0}' ", restrictions[1]); |
||||
if (restrictions != null && restrictions.Length >= 3 && |
||||
restrictions[2] != null) |
||||
{ |
||||
if (where.Length > 0) |
||||
where.Append("AND "); |
||||
where.AppendFormat(CultureInfo.InvariantCulture, "C.table_name='{0}' ", restrictions[2]); |
||||
} |
||||
if (restrictions != null && restrictions.Length == 4 && |
||||
restrictions[3] != null) |
||||
{ |
||||
if (where.Length > 0) |
||||
where.Append("AND "); |
||||
where.AppendFormat(CultureInfo.InvariantCulture, "C.column_name='{0}' ", restrictions[3]); |
||||
} |
||||
if (where.Length > 0) |
||||
sql.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); |
||||
DataTable dt = GetTable(sql.ToString()); |
||||
dt.TableName = "ViewColumns"; |
||||
dt.Columns[0].ColumnName = "VIEW_CATALOG"; |
||||
dt.Columns[1].ColumnName = "VIEW_SCHEMA"; |
||||
dt.Columns[2].ColumnName = "VIEW_NAME"; |
||||
return dt; |
||||
} |
||||
|
||||
private DataTable GetTriggers(string[] restrictions) |
||||
{ |
||||
string[] keys = new string[4]; |
||||
keys[0] = "TRIGGER_CATALOG"; |
||||
keys[1] = "TRIGGER_SCHEMA"; |
||||
keys[2] = "EVENT_OBJECT_TABLE"; |
||||
keys[3] = "TRIGGER_NAME"; |
||||
DataTable dt = Query("TRIGGERS", null, keys, restrictions); |
||||
dt.TableName = "Triggers"; |
||||
return dt; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Return schema information about procedures and functions |
||||
/// Restrictions supported are: |
||||
/// schema, name, type |
||||
/// </summary> |
||||
/// <param name="restrictions"></param> |
||||
/// <returns></returns> |
||||
public override DataTable GetProcedures(string[] restrictions) |
||||
{ |
||||
// if the user has said that we have access to mysql.proc then |
||||
// we use that as it is a lot faster |
||||
// if (connection.HasProcAccess) |
||||
// return base.GetProcedures(restrictions); |
||||
|
||||
string[] keys = new string[4]; |
||||
keys[0] = "ROUTINE_CATALOG"; |
||||
keys[1] = "ROUTINE_SCHEMA"; |
||||
keys[2] = "ROUTINE_NAME"; |
||||
keys[3] = "ROUTINE_TYPE"; |
||||
|
||||
DataTable dt = Query("ROUTINES", null, keys, restrictions); |
||||
dt.TableName = "Procedures"; |
||||
return dt; |
||||
} |
||||
|
||||
private DataTable GetProceduresWithParameters(string[] restrictions) |
||||
{ |
||||
DataTable dt = GetProcedures(restrictions); |
||||
dt.Columns.Add("ParameterList", typeof(string)); |
||||
|
||||
foreach (DataRow row in dt.Rows) |
||||
{ |
||||
row["ParameterList"] = GetProcedureParameterLine(row); |
||||
} |
||||
return dt; |
||||
} |
||||
|
||||
private string GetProcedureParameterLine(DataRow isRow) |
||||
{ |
||||
string sql = "SHOW CREATE {0} `{1}`.`{2}`"; |
||||
sql = String.Format(sql, isRow["ROUTINE_TYPE"], isRow["ROUTINE_SCHEMA"], |
||||
isRow["ROUTINE_NAME"]); |
||||
MySqlCommand cmd = new MySqlCommand(sql, connection); |
||||
using (MySqlDataReader reader = cmd.ExecuteReader()) |
||||
{ |
||||
reader.Read(); |
||||
|
||||
// if we are not the owner of this proc or have permissions |
||||
// then we will get null for the body |
||||
if (reader.IsDBNull(2)) return null; |
||||
|
||||
string sql_mode = reader.GetString(1); |
||||
|
||||
string body = reader.GetString(2); |
||||
MySqlTokenizer tokenizer = new MySqlTokenizer(body); |
||||
tokenizer.AnsiQuotes = sql_mode.IndexOf("ANSI_QUOTES") != -1; |
||||
tokenizer.BackslashEscapes = sql_mode.IndexOf("NO_BACKSLASH_ESCAPES") == -1; |
||||
|
||||
string token = tokenizer.NextToken(); |
||||
while (token != "(") |
||||
token = tokenizer.NextToken(); |
||||
int start = tokenizer.StartIndex + 1; |
||||
token = tokenizer.NextToken(); |
||||
while (token != ")" || tokenizer.Quoted) |
||||
{ |
||||
token = tokenizer.NextToken(); |
||||
// if we see another ( and we are not quoted then we |
||||
// are in a size element and we need to look for the closing paren |
||||
if (token == "(" && !tokenizer.Quoted) |
||||
{ |
||||
while (token != ")" || tokenizer.Quoted) |
||||
token = tokenizer.NextToken(); |
||||
token = tokenizer.NextToken(); |
||||
} |
||||
} |
||||
return body.Substring(start, tokenizer.StartIndex - start); |
||||
} |
||||
} |
||||
|
||||
private void GetParametersForRoutineFromIS(DataTable dt, string[] restrictions) |
||||
{ |
||||
Debug.Assert(dt != null); |
||||
|
||||
string[] keys = new string[5]; |
||||
keys[0] = "SPECIFIC_CATALOG"; |
||||
keys[1] = "SPECIFIC_SCHEMA"; |
||||
keys[2] = "SPECIFIC_NAME"; |
||||
keys[3] = "ROUTINE_TYPE"; |
||||
keys[4] = "PARAMETER_NAME"; |
||||
|
||||
StringBuilder sql = new StringBuilder(@"SELECT * FROM INFORMATION_SCHEMA.PARAMETERS"); |
||||
// now get our where clause and append it if there is one |
||||
string where = GetWhereClause(null, keys, restrictions); |
||||
if (!String.IsNullOrEmpty(where)) |
||||
sql.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); |
||||
|
||||
MySqlDataAdapter da = new MySqlDataAdapter(sql.ToString(), connection); |
||||
da.Fill(dt); |
||||
} |
||||
|
||||
private DataTable GetParametersFromIS(string[] restrictions, DataTable routines) |
||||
{ |
||||
DataTable parms = new DataTable(); |
||||
|
||||
if (routines == null || routines.Rows.Count == 0) |
||||
{ |
||||
if (restrictions == null) |
||||
{ |
||||
// first fill our table with the proper structure |
||||
MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM INFORMATION_SCHEMA.PARAMETERS WHERE 1=2", connection); |
||||
da.Fill(parms); |
||||
} |
||||
else |
||||
GetParametersForRoutineFromIS(parms, restrictions); |
||||
} |
||||
else foreach (DataRow routine in routines.Rows) |
||||
{ |
||||
if (restrictions != null && restrictions.Length >= 3) |
||||
restrictions[2] = routine["ROUTINE_NAME"].ToString(); |
||||
|
||||
GetParametersForRoutineFromIS(parms, restrictions); |
||||
} |
||||
parms.TableName = "Procedure Parameters"; |
||||
return parms; |
||||
} |
||||
|
||||
internal DataTable CreateParametersTable() |
||||
{ |
||||
DataTable dt = new DataTable("Procedure Parameters"); |
||||
dt.Columns.Add("SPECIFIC_CATALOG", typeof(string)); |
||||
dt.Columns.Add("SPECIFIC_SCHEMA", typeof(string)); |
||||
dt.Columns.Add("SPECIFIC_NAME", typeof(string)); |
||||
dt.Columns.Add("ORDINAL_POSITION", typeof(Int32)); |
||||
dt.Columns.Add("PARAMETER_MODE", typeof(string)); |
||||
dt.Columns.Add("PARAMETER_NAME", typeof(string)); |
||||
dt.Columns.Add("DATA_TYPE", typeof(string)); |
||||
dt.Columns.Add("CHARACTER_MAXIMUM_LENGTH", typeof(Int32)); |
||||
dt.Columns.Add("CHARACTER_OCTET_LENGTH", typeof(Int32)); |
||||
dt.Columns.Add("NUMERIC_PRECISION", typeof(byte)); |
||||
dt.Columns.Add("NUMERIC_SCALE", typeof(Int32)); |
||||
dt.Columns.Add("CHARACTER_SET_NAME", typeof(string)); |
||||
dt.Columns.Add("COLLATION_NAME", typeof(string)); |
||||
dt.Columns.Add("DTD_IDENTIFIER", typeof(string)); |
||||
dt.Columns.Add("ROUTINE_TYPE", typeof(string)); |
||||
return dt; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Return schema information about parameters for procedures and functions |
||||
/// Restrictions supported are: |
||||
/// schema, name, type, parameter name |
||||
/// </summary> |
||||
public virtual DataTable GetProcedureParameters(string[] restrictions, |
||||
DataTable routines) |
||||
{ |
||||
if (connection.driver.Version.isAtLeast(6, 0, 6)) |
||||
return GetParametersFromIS(restrictions, routines); |
||||
try |
||||
{ |
||||
DataTable dt = CreateParametersTable(); |
||||
GetParametersFromShowCreate(dt, restrictions, routines); |
||||
return dt; |
||||
} |
||||
catch (InvalidOperationException ioe) |
||||
{ |
||||
throw new InvalidOperationException(Resources.UnableToRetrieveParameters, ioe); |
||||
} |
||||
} |
||||
|
||||
protected override DataTable GetSchemaInternal(string collection, string[] restrictions) |
||||
{ |
||||
DataTable dt = base.GetSchemaInternal(collection, restrictions); |
||||
if (dt != null) |
||||
return dt; |
||||
|
||||
switch (collection) |
||||
{ |
||||
case "VIEWS": |
||||
return GetViews(restrictions); |
||||
case "PROCEDURES": |
||||
return GetProcedures(restrictions); |
||||
case "PROCEDURES WITH PARAMETERS": |
||||
return GetProceduresWithParameters(restrictions); |
||||
case "PROCEDURE PARAMETERS": |
||||
return GetProcedureParameters(restrictions, null); |
||||
case "TRIGGERS": |
||||
return GetTriggers(restrictions); |
||||
case "VIEWCOLUMNS": |
||||
return GetViewColumns(restrictions); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
private static string GetWhereClause(string initial_where, string[] keys, string[] values) |
||||
{ |
||||
StringBuilder where = new StringBuilder(initial_where); |
||||
if (values != null) |
||||
{ |
||||
for (int i = 0; i < keys.Length; i++) |
||||
{ |
||||
if (i >= values.Length) break; |
||||
if (values[i] == null || values[i] == String.Empty) continue; |
||||
if (where.Length > 0) |
||||
where.Append(" AND "); |
||||
where.AppendFormat(CultureInfo.InvariantCulture, |
||||
"{0} LIKE '{1}'", keys[i], values[i]); |
||||
} |
||||
} |
||||
return where.ToString(); |
||||
} |
||||
|
||||
private DataTable Query(string table_name, string initial_where, |
||||
string[] keys, string[] values) |
||||
{ |
||||
StringBuilder query = new StringBuilder("SELECT * FROM INFORMATION_SCHEMA."); |
||||
query.Append(table_name); |
||||
|
||||
string where = GetWhereClause(initial_where, keys, values); |
||||
|
||||
if (where.Length > 0) |
||||
query.AppendFormat(CultureInfo.InvariantCulture, " WHERE {0}", where); |
||||
|
||||
return GetTable(query.ToString()); |
||||
} |
||||
|
||||
private DataTable GetTable(string sql) |
||||
{ |
||||
DataTable table = new DataTable(); |
||||
MySqlDataAdapter da = new MySqlDataAdapter(sql, connection); |
||||
da.Fill(table); |
||||
return table; |
||||
} |
||||
|
||||
public override DataTable GetForeignKeys(string[] restrictions) |
||||
{ |
||||
if (!connection.driver.Version.isAtLeast(5, 1, 16)) |
||||
return base.GetForeignKeys(restrictions); |
||||
|
||||
string sql = @"SELECT rc.constraint_catalog, rc.constraint_schema,
|
||||
rc.constraint_name, kcu.table_catalog, kcu.table_schema, rc.table_name, |
||||
rc.match_option, rc.update_rule, rc.delete_rule, |
||||
NULL as referenced_table_catalog, |
||||
kcu.referenced_table_schema, rc.referenced_table_name |
||||
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc |
||||
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu ON |
||||
kcu.constraint_catalog <=> rc.constraint_catalog AND |
||||
kcu.constraint_schema <=> rc.constraint_schema AND |
||||
kcu.constraint_name <=> rc.constraint_name AND |
||||
kcu.ORDINAL_POSITION=1 WHERE 1=1";
|
||||
|
||||
StringBuilder where =new StringBuilder(); |
||||
if (restrictions.Length >= 2 && !String.IsNullOrEmpty(restrictions[1])) |
||||
where.AppendFormat(CultureInfo.InvariantCulture, |
||||
" AND rc.constraint_schema LIKE '{0}'", restrictions[1]); |
||||
if (restrictions.Length >= 3 && !String.IsNullOrEmpty(restrictions[2])) |
||||
where.AppendFormat(CultureInfo.InvariantCulture, |
||||
" AND rc.table_name LIKE '{0}'", restrictions[2]); |
||||
if (restrictions.Length >= 4 && !String.IsNullOrEmpty(restrictions[3])) |
||||
where.AppendFormat(CultureInfo.InvariantCulture, |
||||
" AND rc.constraint_name LIKE '{0}'", restrictions[2]); |
||||
|
||||
sql += where.ToString(); |
||||
|
||||
return GetTable(sql); |
||||
} |
||||
|
||||
public override DataTable GetForeignKeyColumns(string[] restrictions) |
||||
{ |
||||
if (!connection.driver.Version.isAtLeast(5, 0, 6)) |
||||
return base.GetForeignKeyColumns(restrictions); |
||||
|
||||
string sql = @"SELECT kcu.* FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
||||
WHERE kcu.referenced_table_name IS NOT NULL";
|
||||
|
||||
StringBuilder where = new StringBuilder(); |
||||
if (restrictions.Length >= 2 && !String.IsNullOrEmpty(restrictions[1])) |
||||
where.AppendFormat(CultureInfo.InvariantCulture, |
||||
" AND kcu.constraint_schema LIKE '{0}'", restrictions[1]); |
||||
if (restrictions.Length >= 3 && !String.IsNullOrEmpty(restrictions[2])) |
||||
where.AppendFormat(CultureInfo.InvariantCulture, |
||||
" AND kcu.table_name LIKE '{0}'", restrictions[2]); |
||||
if (restrictions.Length >= 4 && !String.IsNullOrEmpty(restrictions[3])) |
||||
where.AppendFormat(CultureInfo.InvariantCulture, |
||||
" AND kcu.constraint_name LIKE '{0}'", restrictions[3]); |
||||
|
||||
sql += where.ToString(); |
||||
|
||||
return GetTable(sql); |
||||
} |
||||
|
||||
#region Procedures Support Rouines |
||||
|
||||
internal void GetParametersFromShowCreate(DataTable parametersTable, |
||||
string[] restrictions, DataTable routines) |
||||
{ |
||||
// this allows us to pass in a pre-populated routines table |
||||
// and avoid the querying for them again. |
||||
// we use this when calling a procedure or function |
||||
if (routines == null) |
||||
routines = GetSchema("procedures", restrictions); |
||||
|
||||
MySqlCommand cmd = connection.CreateCommand(); |
||||
|
||||
foreach (DataRow routine in routines.Rows) |
||||
{ |
||||
string showCreateSql = String.Format("SHOW CREATE {0} `{1}`.`{2}`", |
||||
routine["ROUTINE_TYPE"], routine["ROUTINE_SCHEMA"], |
||||
routine["ROUTINE_NAME"]); |
||||
cmd.CommandText = showCreateSql; |
||||
try |
||||
{ |
||||
string nameToRestrict = null; |
||||
if (restrictions != null && restrictions.Length == 5 && |
||||
restrictions[4] != null) |
||||
nameToRestrict = restrictions[4]; |
||||
using (MySqlDataReader reader = cmd.ExecuteReader()) |
||||
{ |
||||
reader.Read(); |
||||
string body = reader.GetString(2); |
||||
reader.Close(); |
||||
ParseProcedureBody(parametersTable, body, routine, nameToRestrict); |
||||
} |
||||
} |
||||
catch (SqlNullValueException snex) |
||||
{ |
||||
throw new InvalidOperationException( |
||||
String.Format(Resources.UnableToRetrieveSProcData, routine["ROUTINE_NAME"]), snex); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void ParseProcedureBody(DataTable parametersTable, string body, |
||||
DataRow row, string nameToRestrict) |
||||
{ |
||||
ArrayList modes = new ArrayList(new string[3] { "IN", "OUT", "INOUT" }); |
||||
|
||||
string sqlMode = row["SQL_MODE"].ToString(); |
||||
|
||||
int pos = 1; |
||||
MySqlTokenizer tokenizer = new MySqlTokenizer(body); |
||||
tokenizer.AnsiQuotes = sqlMode.IndexOf("ANSI_QUOTES") != -1; |
||||
tokenizer.BackslashEscapes = sqlMode.IndexOf("NO_BACKSLASH_ESCAPES") == -1; |
||||
tokenizer.ReturnComments = false; |
||||
string token = tokenizer.NextToken(); |
||||
|
||||
// this block will scan for the opening paren while also determining |
||||
// if this routine is a function. If so, then we need to add a |
||||
// parameter row for the return parameter since it is ordinal position |
||||
// 0 and should appear first. |
||||
while (token != "(") |
||||
{ |
||||
if (String.Compare(token, "FUNCTION", true) == 0 && |
||||
nameToRestrict == null) |
||||
{ |
||||
parametersTable.Rows.Add(parametersTable.NewRow()); |
||||
InitParameterRow(row, parametersTable.Rows[0]); |
||||
} |
||||
token = tokenizer.NextToken(); |
||||
} |
||||
token = tokenizer.NextToken(); // now move to the next token past the ( |
||||
|
||||
while (token != ")") |
||||
{ |
||||
DataRow parmRow = parametersTable.NewRow(); |
||||
InitParameterRow(row, parmRow); |
||||
parmRow["ORDINAL_POSITION"] = pos++; |
||||
|
||||
// handle mode and name for the parameter |
||||
string mode = token.ToUpper(CultureInfo.InvariantCulture); |
||||
if (!tokenizer.Quoted && modes.Contains(mode)) |
||||
{ |
||||
parmRow["PARAMETER_MODE"] = mode; |
||||
token = tokenizer.NextToken(); |
||||
} |
||||
if (tokenizer.Quoted) |
||||
token = token.Substring(1, token.Length - 2); |
||||
parmRow["PARAMETER_NAME"] = token; |
||||
|
||||
// now parse data type |
||||
token = ParseDataType(parmRow, tokenizer); |
||||
if (token == ",") |
||||
token = tokenizer.NextToken(); |
||||
|
||||
// now determine if we should include this row after all |
||||
// we need to parse it before this check so we are correctly |
||||
// positioned for the next parameter |
||||
if (nameToRestrict == null || |
||||
String.Compare(parmRow["PARAMETER_NAME"].ToString(), nameToRestrict, true) == 0) |
||||
parametersTable.Rows.Add(parmRow); |
||||
} |
||||
|
||||
// now parse out the return parameter if there is one. |
||||
token = tokenizer.NextToken().ToUpper(CultureInfo.InvariantCulture); |
||||
if (String.Compare(token, "RETURNS", true) == 0) |
||||
{ |
||||
DataRow parameterRow = parametersTable.Rows[0]; |
||||
parameterRow["PARAMETER_NAME"] = "RETURN_VALUE"; |
||||
ParseDataType(parameterRow, tokenizer); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initializes a new row for the procedure parameters table. |
||||
/// </summary> |
||||
private static void InitParameterRow(DataRow procedure, DataRow parameter) |
||||
{ |
||||
parameter["SPECIFIC_CATALOG"] = null; |
||||
parameter["SPECIFIC_SCHEMA"] = procedure["ROUTINE_SCHEMA"]; |
||||
parameter["SPECIFIC_NAME"] = procedure["ROUTINE_NAME"]; |
||||
parameter["PARAMETER_MODE"] = "IN"; |
||||
parameter["ORDINAL_POSITION"] = 0; |
||||
parameter["ROUTINE_TYPE"] = procedure["ROUTINE_TYPE"]; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Parses out the elements of a procedure parameter data type. |
||||
/// </summary> |
||||
private string ParseDataType(DataRow row, MySqlTokenizer tokenizer) |
||||
{ |
||||
StringBuilder dtd = new StringBuilder( |
||||
tokenizer.NextToken().ToUpper(CultureInfo.InvariantCulture)); |
||||
row["DATA_TYPE"] = dtd.ToString(); |
||||
string type = row["DATA_TYPE"].ToString(); |
||||
|
||||
string token = tokenizer.NextToken(); |
||||
if (token == "(") |
||||
{ |
||||
token = tokenizer.ReadParenthesis(); |
||||
dtd.AppendFormat(CultureInfo.InvariantCulture, "{0}", token); |
||||
if (type != "ENUM" && type != "SET") |
||||
ParseDataTypeSize(row, token); |
||||
token = tokenizer.NextToken(); |
||||
} |
||||
else |
||||
dtd.Append(GetDataTypeDefaults(type, row)); |
||||
|
||||
while (token != ")" && |
||||
token != "," && |
||||
String.Compare(token, "begin", true) != 0 && |
||||
String.Compare(token, "return", true) != 0) |
||||
{ |
||||
if (String.Compare(token, "CHARACTER", true) == 0 || |
||||
String.Compare(token, "BINARY", true) == 0) |
||||
{ } // we don't need to do anything with this |
||||
else if (String.Compare(token, "SET", true) == 0 || |
||||
String.Compare(token, "CHARSET", true) == 0) |
||||
row["CHARACTER_SET_NAME"] = tokenizer.NextToken(); |
||||
else if (String.Compare(token, "ASCII", true) == 0) |
||||
row["CHARACTER_SET_NAME"] = "latin1"; |
||||
else if (String.Compare(token, "UNICODE", true) == 0) |
||||
row["CHARACTER_SET_NAME"] = "ucs2"; |
||||
else if (String.Compare(token, "COLLATE", true) == 0) |
||||
row["COLLATION_NAME"] = tokenizer.NextToken(); |
||||
else |
||||
dtd.AppendFormat(CultureInfo.InvariantCulture, " {0}", token); |
||||
token = tokenizer.NextToken(); |
||||
} |
||||
|
||||
if (dtd.Length > 0) |
||||
row["DTD_IDENTIFIER"] = dtd.ToString(); |
||||
|
||||
// now default the collation if one wasn't given |
||||
if (row["COLLATION_NAME"].ToString().Length == 0 && |
||||
row["CHARACTER_SET_NAME"].ToString().Length > 0) |
||||
row["COLLATION_NAME"] = CharSetMap.GetDefaultCollation( |
||||
row["CHARACTER_SET_NAME"].ToString(), connection); |
||||
|
||||
// now set the octet length |
||||
if (row["CHARACTER_MAXIMUM_LENGTH"] != DBNull.Value) |
||||
row["CHARACTER_OCTET_LENGTH"] = |
||||
CharSetMap.GetMaxLength(row["CHARACTER_SET_NAME"].ToString(), connection) * |
||||
(int)row["CHARACTER_MAXIMUM_LENGTH"]; |
||||
|
||||
return token; |
||||
} |
||||
|
||||
private static string GetDataTypeDefaults(string type, DataRow row) |
||||
{ |
||||
string format = "({0},{1})"; |
||||
|
||||
if (MetaData.IsNumericType(type) && |
||||
row["NUMERIC_PRECISION"].ToString().Length == 0) |
||||
{ |
||||
row["NUMERIC_PRECISION"] = 10; |
||||
row["NUMERIC_SCALE"] = 0; |
||||
if (!MetaData.SupportScale(type)) |
||||
format = "({0})"; |
||||
return String.Format(format, row["NUMERIC_PRECISION"], |
||||
row["NUMERIC_SCALE"]); |
||||
} |
||||
return String.Empty; |
||||
} |
||||
|
||||
private static void ParseDataTypeSize(DataRow row, string size) |
||||
{ |
||||
size = size.Trim('(', ')'); |
||||
string[] parts = size.Split(','); |
||||
|
||||
if (!MetaData.IsNumericType(row["DATA_TYPE"].ToString())) |
||||
{ |
||||
row["CHARACTER_MAXIMUM_LENGTH"] = Int32.Parse(parts[0]); |
||||
// will set octet length in a minute |
||||
} |
||||
else |
||||
{ |
||||
row["NUMERIC_PRECISION"] = Int32.Parse(parts[0]); |
||||
if (parts.Length == 2) |
||||
row["NUMERIC_SCALE"] = Int32.Parse(parts[1]); |
||||
} |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
} |
@ -0,0 +1,192 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
#if !MONO && !PocketPC |
||||
|
||||
using System.Configuration.Install; |
||||
using System.ComponentModel; |
||||
using System.Reflection; |
||||
using System; |
||||
using Microsoft.Win32; |
||||
using System.Xml; |
||||
using System.IO; |
||||
using System.Diagnostics; |
||||
using System.Security; |
||||
using System.Security.Permissions; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// We are adding a custom installer class to our assembly so our installer |
||||
/// can make proper changes to the machine.config file. |
||||
/// </summary> |
||||
[RunInstaller(true)] |
||||
public class CustomInstaller : Installer |
||||
{ |
||||
/// <summary> |
||||
/// We override Install so we can add our assembly to the proper |
||||
/// machine.config files. |
||||
/// </summary> |
||||
/// <param name="stateSaver"></param> |
||||
public override void Install(System.Collections.IDictionary stateSaver) |
||||
{ |
||||
base.Install(stateSaver); |
||||
|
||||
AddProviderToMachineConfig(); |
||||
} |
||||
|
||||
private static void AddProviderToMachineConfig() |
||||
{ |
||||
object installRoot = Registry.GetValue( |
||||
@"HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\", |
||||
"InstallRoot", null); |
||||
if (installRoot == null) |
||||
throw new Exception("Unable to retrieve install root for .NET framework"); |
||||
|
||||
AddProviderToMachineConfigInDir(installRoot.ToString()); |
||||
|
||||
string installRoot64 = installRoot.ToString(); |
||||
installRoot64 = installRoot64.Substring(0, installRoot64.Length - 1); |
||||
installRoot64 = string.Format("{0}64{1}", installRoot64, |
||||
Path.DirectorySeparatorChar); |
||||
if (Directory.Exists(installRoot64)) |
||||
AddProviderToMachineConfigInDir(installRoot64); |
||||
} |
||||
|
||||
private static void AddProviderToMachineConfigInDir(string path) |
||||
{ |
||||
string configPath = String.Format(@"{0}v2.0.50727\CONFIG\machine.config", |
||||
path); |
||||
|
||||
// now read the config file into memory |
||||
StreamReader sr = new StreamReader(configPath); |
||||
string configXML = sr.ReadToEnd(); |
||||
sr.Close(); |
||||
|
||||
// load the XML into the XmlDocument |
||||
XmlDocument doc = new XmlDocument(); |
||||
doc.LoadXml(configXML); |
||||
|
||||
// create our new node |
||||
XmlElement newNode = (XmlElement)doc.CreateNode(XmlNodeType.Element, "add", ""); |
||||
|
||||
// add the proper attributes |
||||
newNode.SetAttribute("name", "MySQL Data Provider"); |
||||
newNode.SetAttribute("invariant", "MySql.Data.MySqlClient"); |
||||
newNode.SetAttribute("description", ".Net Framework Data Provider for MySQL"); |
||||
|
||||
// add the type attribute by reflecting on the executing assembly |
||||
Assembly a = Assembly.GetExecutingAssembly(); |
||||
string type = String.Format("MySql.Data.MySqlClient.MySqlClientFactory, {0}", a.FullName); |
||||
newNode.SetAttribute("type", type); |
||||
|
||||
XmlNodeList nodes = doc.GetElementsByTagName("DbProviderFactories"); |
||||
|
||||
foreach (XmlNode node in nodes[0].ChildNodes) |
||||
{ |
||||
if (node.Attributes == null) continue; |
||||
foreach (XmlAttribute attr in node.Attributes) |
||||
{ |
||||
if (attr.Name == "invariant" && attr.Value == "MySql.Data.MySqlClient") |
||||
{ |
||||
nodes[0].RemoveChild(node); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
nodes[0].AppendChild(newNode); |
||||
|
||||
// Save the document to a file and auto-indent the output. |
||||
XmlTextWriter writer = new XmlTextWriter(configPath, null); |
||||
writer.Formatting = Formatting.Indented; |
||||
doc.Save(writer); |
||||
writer.Flush(); |
||||
writer.Close(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// We override Uninstall so we can remove out assembly from the |
||||
/// machine.config files. |
||||
/// </summary> |
||||
/// <param name="savedState"></param> |
||||
public override void Uninstall(System.Collections.IDictionary savedState) |
||||
{ |
||||
base.Uninstall(savedState); |
||||
|
||||
RemoveProviderFromMachineConfig(); |
||||
} |
||||
|
||||
private static void RemoveProviderFromMachineConfig() |
||||
{ |
||||
object installRoot = Registry.GetValue( |
||||
@"HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\", |
||||
"InstallRoot", null); |
||||
if (installRoot == null) |
||||
throw new Exception("Unable to retrieve install root for .NET framework"); |
||||
|
||||
|
||||
RemoveProviderFromMachineConfigInDir(installRoot.ToString()); |
||||
|
||||
string installRoot64 = installRoot.ToString(); |
||||
installRoot64 = installRoot64.Substring(0, installRoot64.Length - 1); |
||||
installRoot64 = string.Format("{0}64{1}", installRoot64, |
||||
Path.DirectorySeparatorChar); |
||||
if (Directory.Exists(installRoot64)) |
||||
RemoveProviderFromMachineConfigInDir(installRoot64); |
||||
} |
||||
|
||||
private static void RemoveProviderFromMachineConfigInDir(string path) |
||||
{ |
||||
string configPath = String.Format(@"{0}v2.0.50727\CONFIG\machine.config", |
||||
path); |
||||
|
||||
// now read the config file into memory |
||||
StreamReader sr = new StreamReader(configPath); |
||||
string configXML = sr.ReadToEnd(); |
||||
sr.Close(); |
||||
|
||||
// load the XML into the XmlDocument |
||||
XmlDocument doc = new XmlDocument(); |
||||
doc.LoadXml(configXML); |
||||
|
||||
XmlNodeList nodes = doc.GetElementsByTagName("DbProviderFactories"); |
||||
foreach (XmlNode node in nodes[0].ChildNodes) |
||||
{ |
||||
if (node.Attributes == null) continue; |
||||
string name = node.Attributes["name"].Value; |
||||
if (name == "MySQL Data Provider") |
||||
{ |
||||
nodes[0].RemoveChild(node); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// Save the document to a file and auto-indent the output. |
||||
XmlTextWriter writer = new XmlTextWriter(configPath, null); |
||||
writer.Formatting = Formatting.Indented; |
||||
doc.Save(writer); |
||||
writer.Flush(); |
||||
writer.Close(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,159 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
#if !PocketPC |
||||
|
||||
using System.Data.Common; |
||||
using System; |
||||
using System.Reflection; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// DBProviderFactory implementation for MysqlClient. |
||||
/// </summary> |
||||
public sealed class MySqlClientFactory : DbProviderFactory, IServiceProvider |
||||
{ |
||||
/// <summary> |
||||
/// Gets an instance of the <see cref="MySqlClientFactory"/>. |
||||
/// This can be used to retrieve strongly typed data objects. |
||||
/// </summary> |
||||
public static MySqlClientFactory Instance = new MySqlClientFactory(); |
||||
private Type dbServicesType; |
||||
private FieldInfo mySqlDbProviderServicesInstance; |
||||
|
||||
/// <summary> |
||||
/// Returns a strongly typed <see cref="DbCommandBuilder"/> instance. |
||||
/// </summary> |
||||
/// <returns>A new strongly typed instance of <b>DbCommandBuilder</b>.</returns> |
||||
public override DbCommandBuilder CreateCommandBuilder() |
||||
{ |
||||
return new MySqlCommandBuilder(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a strongly typed <see cref="DbCommand"/> instance. |
||||
/// </summary> |
||||
/// <returns>A new strongly typed instance of <b>DbCommand</b>.</returns> |
||||
public override DbCommand CreateCommand() |
||||
{ |
||||
return new MySqlCommand(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a strongly typed <see cref="DbConnection"/> instance. |
||||
/// </summary> |
||||
/// <returns>A new strongly typed instance of <b>DbConnection</b>.</returns> |
||||
public override DbConnection CreateConnection() |
||||
{ |
||||
return new MySqlConnection(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a strongly typed <see cref="DbDataAdapter"/> instance. |
||||
/// </summary> |
||||
/// <returns>A new strongly typed instance of <b>DbDataAdapter</b>. </returns> |
||||
public override DbDataAdapter CreateDataAdapter() |
||||
{ |
||||
return new MySqlDataAdapter(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a strongly typed <see cref="DbParameter"/> instance. |
||||
/// </summary> |
||||
/// <returns>A new strongly typed instance of <b>DbParameter</b>.</returns> |
||||
public override DbParameter CreateParameter() |
||||
{ |
||||
return new MySqlParameter(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a strongly typed <see cref="DbConnectionStringBuilder"/> instance. |
||||
/// </summary> |
||||
/// <returns>A new strongly typed instance of <b>DbConnectionStringBuilder</b>.</returns> |
||||
public override DbConnectionStringBuilder CreateConnectionStringBuilder() |
||||
{ |
||||
return new MySqlConnectionStringBuilder(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns true if a <b>MySqlDataSourceEnumerator</b> can be created; |
||||
/// otherwise false. |
||||
/// </summary> |
||||
public override bool CanCreateDataSourceEnumerator |
||||
{ |
||||
get { return false; } |
||||
} |
||||
|
||||
#region IServiceProvider Members |
||||
|
||||
/// <summary> |
||||
/// Provide a simple caching layer |
||||
/// </summary> |
||||
private Type DbServicesType |
||||
{ |
||||
get |
||||
{ |
||||
if (dbServicesType == null) |
||||
{ |
||||
// Get the type this way so we don't have to reference System.Data.Entity |
||||
// from our core provider |
||||
dbServicesType = Type.GetType( |
||||
@"System.Data.Common.DbProviderServices, System.Data.Entity,
|
||||
Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
|
||||
false); |
||||
} |
||||
return dbServicesType; |
||||
} |
||||
} |
||||
|
||||
private FieldInfo MySqlDbProviderServicesInstance |
||||
{ |
||||
get |
||||
{ |
||||
if (mySqlDbProviderServicesInstance == null) |
||||
{ |
||||
string fullName = Assembly.GetExecutingAssembly().FullName; |
||||
fullName = fullName.Replace("MySql.Data", "MySql.Data.Entity"); |
||||
fullName = String.Format("MySql.Data.MySqlClient.MySqlProviderServices, {0}", fullName); |
||||
|
||||
Type providerServicesType = Type.GetType(fullName, false); |
||||
mySqlDbProviderServicesInstance = providerServicesType.GetField("Instance", |
||||
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); |
||||
} |
||||
return mySqlDbProviderServicesInstance; |
||||
} |
||||
} |
||||
|
||||
object IServiceProvider.GetService(Type serviceType) |
||||
{ |
||||
// DbProviderServices is the only service we offer up right now |
||||
if (serviceType != DbServicesType) return null; |
||||
|
||||
if (MySqlDbProviderServicesInstance == null) return null; |
||||
|
||||
return MySqlDbProviderServicesInstance.GetValue(null); |
||||
} |
||||
|
||||
#endregion |
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,929 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data.Common; |
||||
using System.Collections.Generic; |
||||
using System.ComponentModel; |
||||
using System.Reflection; |
||||
using System.Text.RegularExpressions; |
||||
using System.Text; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using System.Collections; |
||||
using System.Globalization; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
public class MySqlConnectionStringBuilder : DbConnectionStringBuilder |
||||
{ |
||||
private static Dictionary<string, string> validKeywords = |
||||
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); |
||||
private static Dictionary<string, PropertyDefaultValue> defaultValues = |
||||
new Dictionary<string, PropertyDefaultValue>(StringComparer.OrdinalIgnoreCase); |
||||
private Dictionary<string, object> values = |
||||
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); |
||||
|
||||
static MySqlConnectionStringBuilder() |
||||
{ |
||||
// load up our valid keywords and default values only once |
||||
Initialize(); |
||||
} |
||||
|
||||
public MySqlConnectionStringBuilder() |
||||
{ |
||||
Clear(); |
||||
} |
||||
|
||||
public MySqlConnectionStringBuilder(string connStr) |
||||
: this() |
||||
{ |
||||
ConnectionString = connStr; |
||||
} |
||||
|
||||
#region Server Properties |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the name of the server. |
||||
/// </summary> |
||||
/// <value>The server.</value> |
||||
[Category("Connection")] |
||||
[Description("Server to connect to")] |
||||
[DefaultValue("")] |
||||
[ValidKeywords("host, data source, datasource, address, addr, network address")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string Server |
||||
{ |
||||
get { return values["server"] as string; } |
||||
set { SetValue("server", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the name of the database the connection should |
||||
/// initially connect to. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[Description("Database to use initially")] |
||||
[DefaultValue("")] |
||||
[ValidKeywords("initial catalog")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string Database |
||||
{ |
||||
get { return values["database"] as string; } |
||||
set { SetValue("database", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the protocol that should be used for communicating |
||||
/// with MySQL. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[DisplayName("Connection Protocol")] |
||||
[Description("Protocol to use for connection to MySQL")] |
||||
[DefaultValue(MySqlConnectionProtocol.Sockets)] |
||||
[ValidKeywords("protocol")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public MySqlConnectionProtocol ConnectionProtocol |
||||
{ |
||||
get { return (MySqlConnectionProtocol)values["Connection Protocol"]; } |
||||
set { SetValue("Connection Protocol", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the name of the named pipe that should be used |
||||
/// for communicating with MySQL. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[DisplayName("Pipe Name")] |
||||
[Description("Name of pipe to use when connecting with named pipes (Win32 only)")] |
||||
[DefaultValue("MYSQL")] |
||||
[ValidKeywords("pipe")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string PipeName |
||||
{ |
||||
get { return (string)values["Pipe Name"]; } |
||||
set { SetValue("Pipe Name", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value that indicates whether this connection |
||||
/// should use compression. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[DisplayName("Use Compression")] |
||||
[Description("Should the connection ues compression")] |
||||
[DefaultValue(false)] |
||||
[ValidKeywords("compress")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool UseCompression |
||||
{ |
||||
get { return (bool)values["Use Compression"]; } |
||||
set { SetValue("Use Compression", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value that indicates whether this connection will allow |
||||
/// commands to send multiple SQL statements in one execution. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[DisplayName("Allow Batch")] |
||||
[Description("Allows execution of multiple SQL commands in a single statement")] |
||||
[DefaultValue(true)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool AllowBatch |
||||
{ |
||||
get { return (bool)values["Allow Batch"]; } |
||||
set { SetValue("Allow Batch", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value that indicates whether logging is enabled. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[Description("Enables output of diagnostic messages")] |
||||
[DefaultValue(false)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool Logging |
||||
{ |
||||
get { return (bool)values["Logging"]; } |
||||
set { SetValue("Logging", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the base name of the shared memory objects used to |
||||
/// communicate with MySQL when the shared memory protocol is being used. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[DisplayName("Shared Memory Name")] |
||||
[Description("Name of the shared memory object to use")] |
||||
[DefaultValue("MYSQL")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string SharedMemoryName |
||||
{ |
||||
get { return (string)values["Shared Memory Name"]; } |
||||
set { SetValue("Shared Memory Name", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value that indicates whether this connection uses |
||||
/// the old style (@) parameter markers or the new (?) style. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[DisplayName("Use Old Syntax")] |
||||
[Description("Allows the use of old style @ syntax for parameters")] |
||||
[DefaultValue(false)] |
||||
[ValidKeywords("old syntax, oldsyntax")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
[Obsolete("Use Old Syntax is no longer needed. See documentation")] |
||||
public bool UseOldSyntax |
||||
{ |
||||
get { return (bool)values["Use Old Syntax"]; } |
||||
set { SetValue("Use Old Syntax", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the port number that is used when the socket |
||||
/// protocol is being used. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[Description("Port to use for TCP/IP connections")] |
||||
[DefaultValue(3306)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public uint Port |
||||
{ |
||||
get { return (uint)values["Port"]; } |
||||
set { SetValue("Port", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the connection timeout. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[DisplayName("Connect Timeout")] |
||||
[Description("The length of time (in seconds) to wait for a connection " + |
||||
"to the server before terminating the attempt and generating an error.")] |
||||
[DefaultValue(15)] |
||||
[ValidKeywords("connection timeout")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public uint ConnectionTimeout |
||||
{ |
||||
get { return (uint)values["Connect Timeout"]; } |
||||
|
||||
set |
||||
{ |
||||
// Timeout in milliseconds should not exceed maximum for 32 bit |
||||
// signed integer (~24 days). We truncate the value if it exceeds |
||||
// maximum (MySqlCommand.CommandTimeout uses the same technique |
||||
uint timeout = Math.Min(value, Int32.MaxValue / 1000); |
||||
if (timeout != value) |
||||
{ |
||||
MySqlTrace.LogWarning(-1, "Connection timeout value too large (" |
||||
+ value + " seconds). Changed to max. possible value" + |
||||
+ timeout + " seconds)"); |
||||
} |
||||
SetValue("Connect Timeout", timeout); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the default command timeout. |
||||
/// </summary> |
||||
[Category("Connection")] |
||||
[DisplayName("Default Command Timeout")] |
||||
[Description(@"The default timeout that MySqlCommand objects will use
|
||||
unless changed.")]
|
||||
[DefaultValue(30)] |
||||
[ValidKeywords("command timeout")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public uint DefaultCommandTimeout |
||||
{ |
||||
get { return (uint)values["Default Command Timeout"]; } |
||||
set { SetValue("Default Command Timeout", value); } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Authentication Properties |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the user id that should be used to connect with. |
||||
/// </summary> |
||||
[Category("Security")] |
||||
[DisplayName("User Id")] |
||||
[Description("Indicates the user ID to be used when connecting to the data source.")] |
||||
[DefaultValue("")] |
||||
[ValidKeywords("uid, username, user name, user")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string UserID |
||||
{ |
||||
get { return (string)values["User Id"]; } |
||||
set { SetValue("User Id", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the password that should be used to connect with. |
||||
/// </summary> |
||||
[Category("Security")] |
||||
[Description("Indicates the password to be used when connecting to the data source.")] |
||||
[PasswordPropertyText(true)] |
||||
[DefaultValue("")] |
||||
[ValidKeywords("pwd")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string Password |
||||
{ |
||||
get { return (string)values["Password"]; } |
||||
set { SetValue("Password", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value that indicates if the password should be persisted |
||||
/// in the connection string. |
||||
/// </summary> |
||||
[Category("Security")] |
||||
[DisplayName("Persist Security Info")] |
||||
[Description("When false, security-sensitive information, such as the password, " + |
||||
"is not returned as part of the connection if the connection is open or " + |
||||
"has ever been in an open state.")] |
||||
[DefaultValue(false)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool PersistSecurityInfo |
||||
{ |
||||
get { return (bool)values["Persist Security Info"]; } |
||||
set { SetValue("Persist Security Info", value); } |
||||
} |
||||
|
||||
[Category("Authentication")] |
||||
[Description("Should the connection use SSL.")] |
||||
[DefaultValue(false)] |
||||
[Obsolete("Use Ssl Mode instead.")] |
||||
internal bool Encrypt |
||||
{ |
||||
get { return SslMode != MySqlSslMode.None; } |
||||
set |
||||
{ |
||||
SetValue("Ssl Mode", value ? MySqlSslMode.Prefered : MySqlSslMode.None); |
||||
} |
||||
} |
||||
|
||||
[Category("Authentication")] |
||||
[DisplayName("Certificate File")] |
||||
[Description("Certificate file in PKCS#12 format (.pfx)")] |
||||
[DefaultValue(null)] |
||||
public string CertificateFile |
||||
{ |
||||
get { return (string) values["Certificate File"];} |
||||
set |
||||
{ |
||||
SetValue("Certificate File", value); |
||||
} |
||||
} |
||||
|
||||
[Category("Authentication")] |
||||
[DisplayName("Certificate Password")] |
||||
[Description("Password for certificate file")] |
||||
[DefaultValue(null)] |
||||
public string CertificatePassword |
||||
{ |
||||
get { return (string)values["Certificate Password"];} |
||||
set |
||||
{ |
||||
SetValue("Certificate Password", value); |
||||
} |
||||
} |
||||
|
||||
[Category("Authentication")] |
||||
[DisplayName("Certificate Store Location")] |
||||
[Description("Certificate Store Location for client certificates")] |
||||
[DefaultValue(MySqlCertificateStoreLocation.None)] |
||||
public MySqlCertificateStoreLocation CertificateStoreLocation |
||||
{ |
||||
get { return (MySqlCertificateStoreLocation)values["Certificate Store Location"]; } |
||||
set |
||||
{ |
||||
SetValue("Certificate Store Location", value); |
||||
} |
||||
} |
||||
|
||||
[Category("Authentication")] |
||||
[DisplayName("Certificate Thumbprint")] |
||||
[Description("Certificate thumbprint. Can be used together with Certificate "+ |
||||
"Store Location parameter to uniquely identify certificate to be used "+ |
||||
"for SSL authentication.")] |
||||
[DefaultValue(null)] |
||||
public string CertificateThumbprint |
||||
{ |
||||
get { return (string)values["Certificate Thumbprint"]; } |
||||
set |
||||
{ |
||||
SetValue("Certificate Thumbprint", value); |
||||
} |
||||
} |
||||
#endregion |
||||
|
||||
#region Other Properties |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value that indicates if zero date time values are supported. |
||||
/// </summary> |
||||
[Category("Advanced")] |
||||
[DisplayName("Allow Zero Datetime")] |
||||
[Description("Should zero datetimes be supported")] |
||||
[DefaultValue(false)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool AllowZeroDateTime |
||||
{ |
||||
get { return (bool)values["Allow Zero Datetime"]; } |
||||
set { SetValue("Allow Zero DateTime", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value indicating if zero datetime values should be |
||||
/// converted to DateTime.MinValue. |
||||
/// </summary> |
||||
[Category("Advanced")] |
||||
[DisplayName("Convert Zero Datetime")] |
||||
[Description("Should illegal datetime values be converted to DateTime.MinValue")] |
||||
[DefaultValue(false)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool ConvertZeroDateTime |
||||
{ |
||||
get { return (bool)values["Convert Zero Datetime"]; } |
||||
set { SetValue("Convert Zero DateTime", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value indicating if the Usage Advisor should be enabled. |
||||
/// </summary> |
||||
[Category("Advanced")] |
||||
[DisplayName("Use Usage Advisor")] |
||||
[Description("Logs inefficient database operations")] |
||||
[DefaultValue(false)] |
||||
[ValidKeywords("usage advisor")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool UseUsageAdvisor |
||||
{ |
||||
get { return (bool)values["Use Usage Advisor"]; } |
||||
set { SetValue("Use Usage Advisor", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the size of the stored procedure cache. |
||||
/// </summary> |
||||
[Category("Advanced")] |
||||
[DisplayName("Procedure Cache Size")] |
||||
[Description("Indicates how many stored procedures can be cached at one time. " + |
||||
"A value of 0 effectively disables the procedure cache.")] |
||||
[DefaultValue(25)] |
||||
[ValidKeywords("procedure cache, procedurecache")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public uint ProcedureCacheSize |
||||
{ |
||||
get { return (uint)values["Procedure Cache Size"]; } |
||||
set { SetValue("Procedure Cache Size", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value indicating if the permon hooks should be enabled. |
||||
/// </summary> |
||||
[Category("Advanced")] |
||||
[DisplayName("Use Performance Monitor")] |
||||
[Description("Indicates that performance counters should be updated during execution.")] |
||||
[DefaultValue(false)] |
||||
[ValidKeywords("userperfmon, perfmon")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool UsePerformanceMonitor |
||||
{ |
||||
get { return (bool)values["Use Performance Monitor"]; } |
||||
set { SetValue("Use Performance Monitor", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value indicating if calls to Prepare() should be ignored. |
||||
/// </summary> |
||||
[Category("Advanced")] |
||||
[DisplayName("Ignore Prepare")] |
||||
[Description("Instructs the provider to ignore any attempts to prepare a command.")] |
||||
[DefaultValue(true)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool IgnorePrepare |
||||
{ |
||||
get { return (bool)values["Ignore Prepare"]; } |
||||
set { SetValue("Ignore Prepare", value); } |
||||
} |
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Use Procedure Bodies")] |
||||
[Description("Indicates if stored procedure bodies will be available for parameter detection.")] |
||||
[DefaultValue(true)] |
||||
[ValidKeywords("procedure bodies")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool UseProcedureBodies |
||||
{ |
||||
get { return (bool)values["Use Procedure Bodies"]; } |
||||
set { SetValue("Use Procedure Bodies", value); } |
||||
} |
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Auto Enlist")] |
||||
[Description("Should the connetion automatically enlist in the active connection, if there are any.")] |
||||
[DefaultValue(true)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool AutoEnlist |
||||
{ |
||||
get { return (bool)values["Auto Enlist"]; } |
||||
set { SetValue("Auto Enlist", value); } |
||||
} |
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Respect Binary Flags")] |
||||
[Description("Should binary flags on column metadata be respected.")] |
||||
[DefaultValue(true)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool RespectBinaryFlags |
||||
{ |
||||
get { return (bool)values["Respect Binary Flags"]; } |
||||
set { SetValue("Respect Binary Flags", value); } |
||||
} |
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Treat Tiny As Boolean")] |
||||
[Description("Should the provider treat TINYINT(1) columns as boolean.")] |
||||
[DefaultValue(true)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool TreatTinyAsBoolean |
||||
{ |
||||
get { return (bool)values["Treat Tiny As Boolean"]; } |
||||
set { SetValue("Treat Tiny As Boolean", value); } |
||||
} |
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Allow User Variables")] |
||||
[Description("Should the provider expect user variables to appear in the SQL.")] |
||||
[DefaultValue(false)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool AllowUserVariables |
||||
{ |
||||
get { return (bool)values["Allow User Variables"]; } |
||||
set { SetValue("Allow User Variables", value); } |
||||
} |
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Interactive Session")] |
||||
[Description("Should this session be considered interactive?")] |
||||
[DefaultValue(false)] |
||||
[ValidKeywords("interactive")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool InteractiveSession |
||||
{ |
||||
get { return (bool)values["Interactive Session"]; } |
||||
set { SetValue("Interactive Session", value); } |
||||
} |
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Functions Return String")] |
||||
[Description("Should all server functions be treated as returning string?")] |
||||
[DefaultValue(false)] |
||||
public bool FunctionsReturnString |
||||
{ |
||||
get { return (bool)values["Functions Return String"]; } |
||||
set { SetValue("Functions Return String", value); } |
||||
} |
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Use Affected Rows")] |
||||
[Description("Should the returned affected row count reflect affected rows instead of found rows?")] |
||||
[DefaultValue(false)] |
||||
public bool UseAffectedRows |
||||
{ |
||||
get { return (bool)values["Use Affected Rows"]; } |
||||
set { SetValue("Use Affected Rows", value); } |
||||
} |
||||
|
||||
|
||||
[Category("Advanced")] |
||||
[DisplayName("Old Guids")] |
||||
[Description("Treat binary(16) columns as guids")] |
||||
[DefaultValue(false)] |
||||
public bool OldGuids |
||||
{ |
||||
get { return (bool)values["Old Guids"]; } |
||||
set { SetValue("Old Guids", value); } |
||||
} |
||||
|
||||
[DisplayName("Keep Alive")] |
||||
[Description("For TCP connections, idle connection time measured in seconds, before the first keepalive packet is sent." + |
||||
"A value of 0 indicates that keepalive is not used.")] |
||||
[DefaultValue(0)] |
||||
public uint Keepalive |
||||
{ |
||||
get { return (uint)values["Keep Alive"]; } |
||||
set { SetValue("Keep Alive", value); } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Pooling Properties |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the lifetime of a pooled connection. |
||||
/// </summary> |
||||
[Category("Pooling")] |
||||
[DisplayName("Connection Lifetime")] |
||||
[Description("The minimum amount of time (in seconds) for this connection to " + |
||||
"live in the pool before being destroyed.")] |
||||
[DefaultValue(0)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public uint ConnectionLifeTime |
||||
{ |
||||
get { return (uint)values["Connection LifeTime"]; } |
||||
set { SetValue("Connection LifeTime", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value indicating if connection pooling is enabled. |
||||
/// </summary> |
||||
[Category("Pooling")] |
||||
[Description("When true, the connection object is drawn from the appropriate " + |
||||
"pool, or if necessary, is created and added to the appropriate pool.")] |
||||
[DefaultValue(true)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool Pooling |
||||
{ |
||||
get { return (bool)values["Pooling"]; } |
||||
set { SetValue("Pooling", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the minimum connection pool size. |
||||
/// </summary> |
||||
[Category("Pooling")] |
||||
[DisplayName("Minimum Pool Size")] |
||||
[Description("The minimum number of connections allowed in the pool.")] |
||||
[DefaultValue(0)] |
||||
[ValidKeywords("min pool size")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public uint MinimumPoolSize |
||||
{ |
||||
get { return (uint)values["Minimum Pool Size"]; } |
||||
set { SetValue("Minimum Pool Size", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the maximum connection pool setting. |
||||
/// </summary> |
||||
[Category("Pooling")] |
||||
[DisplayName("Maximum Pool Size")] |
||||
[Description("The maximum number of connections allowed in the pool.")] |
||||
[DefaultValue(100)] |
||||
[ValidKeywords("max pool size")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public uint MaximumPoolSize |
||||
{ |
||||
get { return (uint)values["Maximum Pool Size"]; } |
||||
set { SetValue("Maximum Pool Size", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a boolean value indicating if the connection should be reset when retrieved |
||||
/// from the pool. |
||||
/// </summary> |
||||
[Category("Pooling")] |
||||
[DisplayName("Connection Reset")] |
||||
[Description("When true, indicates the connection state is reset when " + |
||||
"removed from the pool.")] |
||||
[DefaultValue(false)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool ConnectionReset |
||||
{ |
||||
get { return (bool)values["Connection Reset"]; } |
||||
set { SetValue("Connection Reset", value); } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Language and Character Set Properties |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the character set that should be used for sending queries to the server. |
||||
/// </summary> |
||||
[DisplayName("Character Set")] |
||||
[Category("Advanced")] |
||||
[Description("Character set this connection should use")] |
||||
[DefaultValue("")] |
||||
[ValidKeywords("charset")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string CharacterSet |
||||
{ |
||||
get { return (string)values["Character Set"]; } |
||||
set { SetValue("Character Set", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Indicates whether the driver should treat binary blobs as UTF8 |
||||
/// </summary> |
||||
[DisplayName("Treat Blobs As UTF8")] |
||||
[Category("Advanced")] |
||||
[Description("Should binary blobs be treated as UTF8")] |
||||
[DefaultValue(false)] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public bool TreatBlobsAsUTF8 |
||||
{ |
||||
get { return (bool)values["Treat Blobs As UTF8"]; } |
||||
set { SetValue("Treat Blobs As UTF8", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the pattern that matches the columns that should be treated as UTF8 |
||||
/// </summary> |
||||
[Category("Advanced")] |
||||
[Description("Pattern that matches columns that should be treated as UTF8")] |
||||
[DefaultValue("")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string BlobAsUTF8IncludePattern |
||||
{ |
||||
get { return (string)values["BlobAsUTF8IncludePattern"]; } |
||||
set { SetValue("BlobAsUTF8IncludePattern", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the pattern that matches the columns that should not be treated as UTF8 |
||||
/// </summary> |
||||
[Category("Advanced")] |
||||
[Description("Pattern that matches columns that should not be treated as UTF8")] |
||||
[DefaultValue("")] |
||||
[RefreshProperties(RefreshProperties.All)] |
||||
public string BlobAsUTF8ExcludePattern |
||||
{ |
||||
get { return (string)values["BlobAsUTF8ExcludePattern"]; } |
||||
set { SetValue("BlobAsUTF8ExcludePattern", value); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Indicates whether to use SSL connections and how to handle server certificate errors. |
||||
/// </summary> |
||||
[DisplayName("Ssl Mode")] |
||||
[Category("Security")] |
||||
[Description("SSL properties for connection")] |
||||
[DefaultValue(MySqlSslMode.None)] |
||||
public MySqlSslMode SslMode |
||||
{ |
||||
get { return (MySqlSslMode)values["Ssl Mode"]; } |
||||
set { SetValue("Ssl Mode", value); } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal Regex GetBlobAsUTF8IncludeRegex() |
||||
{ |
||||
if (String.IsNullOrEmpty(BlobAsUTF8IncludePattern)) return null; |
||||
return new Regex(BlobAsUTF8IncludePattern); |
||||
} |
||||
|
||||
internal Regex GetBlobAsUTF8ExcludeRegex() |
||||
{ |
||||
if (String.IsNullOrEmpty(BlobAsUTF8ExcludePattern)) return null; |
||||
return new Regex(BlobAsUTF8ExcludePattern); |
||||
} |
||||
|
||||
public override object this[string keyword] |
||||
{ |
||||
get { return values[validKeywords[keyword]]; } |
||||
set |
||||
{ |
||||
ValidateKeyword(keyword); |
||||
if (value == null) |
||||
Remove(keyword); |
||||
else |
||||
SetValue(keyword, value); |
||||
} |
||||
} |
||||
|
||||
public override void Clear() |
||||
{ |
||||
base.Clear(); |
||||
|
||||
// make a copy of our default values array |
||||
foreach (string key in defaultValues.Keys) |
||||
values[key] = defaultValues[key].DefaultValue; |
||||
} |
||||
|
||||
#if !CF |
||||
|
||||
public override bool Remove(string keyword) |
||||
{ |
||||
ValidateKeyword(keyword); |
||||
string primaryKey = validKeywords[keyword]; |
||||
|
||||
values.Remove(primaryKey); |
||||
base.Remove(primaryKey); |
||||
|
||||
values[primaryKey] = defaultValues[primaryKey].DefaultValue; |
||||
return true; |
||||
} |
||||
|
||||
public override bool TryGetValue(string keyword, out object value) |
||||
{ |
||||
ValidateKeyword(keyword); |
||||
return values.TryGetValue(validKeywords[keyword], out value); |
||||
} |
||||
|
||||
#endif |
||||
|
||||
public string GetConnectionString(bool includePass) |
||||
{ |
||||
if (includePass) return ConnectionString; |
||||
|
||||
StringBuilder conn = new StringBuilder(); |
||||
string delimiter = ""; |
||||
foreach (string key in this.Keys) |
||||
{ |
||||
if (String.Compare(key, "password", true) == 0 || |
||||
String.Compare(key, "pwd", true) == 0) continue; |
||||
conn.AppendFormat(CultureInfo.CurrentCulture, "{0}{1}={2}", |
||||
delimiter, key, this[key]); |
||||
delimiter = ";"; |
||||
} |
||||
return conn.ToString(); |
||||
} |
||||
|
||||
private void SetValue(string keyword, object value) |
||||
{ |
||||
ValidateKeyword(keyword); |
||||
keyword = validKeywords[keyword]; |
||||
|
||||
Remove(keyword); |
||||
|
||||
object val = null; |
||||
if (value is string && defaultValues[keyword].DefaultValue is Enum) |
||||
val = ParseEnum(defaultValues[keyword].Type, (string)value, keyword); |
||||
else |
||||
val = ChangeType(value, defaultValues[keyword].Type); |
||||
values[keyword] = val; |
||||
base[keyword] = val; |
||||
} |
||||
|
||||
private object ParseEnum(Type t, string requestedValue, string key) |
||||
{ |
||||
try |
||||
{ |
||||
return Enum.Parse(t, requestedValue, true); |
||||
} |
||||
catch (ArgumentException) |
||||
{ |
||||
throw new InvalidOperationException(String.Format( |
||||
Resources.InvalidConnectionStringValue, requestedValue, key)); |
||||
} |
||||
} |
||||
|
||||
private object ChangeType(object value, Type t) |
||||
{ |
||||
if (t == typeof(bool) && value is string) |
||||
{ |
||||
string s = value.ToString().ToLower(CultureInfo.InvariantCulture); |
||||
if (s == "yes" || s == "true") return true; |
||||
if (s == "no" || s == "false") return false; |
||||
throw new FormatException(String.Format(Resources.InvalidValueForBoolean, value)); |
||||
} |
||||
else |
||||
return Convert.ChangeType(value, t, CultureInfo.CurrentCulture); |
||||
} |
||||
|
||||
private void ValidateKeyword(string keyword) |
||||
{ |
||||
string key = keyword.ToLower(CultureInfo.InvariantCulture); |
||||
if (!validKeywords.ContainsKey(key)) |
||||
throw new ArgumentException(Resources.KeywordNotSupported, keyword); |
||||
if (validKeywords[key] == "Use Old Syntax") |
||||
MySqlTrace.LogWarning(-1, "Use Old Syntax is now obsolete. Please see documentation"); |
||||
if (validKeywords[key] == "Encrypt") |
||||
MySqlTrace.LogWarning(-1, "Encrypt is now obsolete. Use Ssl Mode instead"); |
||||
} |
||||
|
||||
private static void Initialize() |
||||
{ |
||||
PropertyInfo[] properties = typeof(MySqlConnectionStringBuilder).GetProperties(); |
||||
foreach (PropertyInfo pi in properties) |
||||
AddKeywordFromProperty(pi); |
||||
|
||||
// remove this starting with 6.4 |
||||
PropertyInfo encrypt = typeof(MySqlConnectionStringBuilder).GetProperty( |
||||
"Encrypt", BindingFlags.Instance | BindingFlags.NonPublic); |
||||
AddKeywordFromProperty(encrypt); |
||||
} |
||||
|
||||
private static void AddKeywordFromProperty(PropertyInfo pi) |
||||
{ |
||||
string name = pi.Name.ToLower(CultureInfo.InvariantCulture); |
||||
string displayName = name; |
||||
|
||||
// now see if we have defined a display name for this property |
||||
object[] attr = pi.GetCustomAttributes(false); |
||||
foreach (Attribute a in attr) |
||||
if (a is DisplayNameAttribute) |
||||
{ |
||||
displayName = (a as DisplayNameAttribute).DisplayName; |
||||
break; |
||||
} |
||||
|
||||
validKeywords[name] = displayName; |
||||
validKeywords[displayName] = displayName; |
||||
|
||||
foreach (Attribute a in attr) |
||||
{ |
||||
if (a is ValidKeywordsAttribute) |
||||
{ |
||||
foreach (string keyword in (a as ValidKeywordsAttribute).Keywords) |
||||
validKeywords[keyword.ToLower(CultureInfo.InvariantCulture).Trim()] = displayName; |
||||
} |
||||
else if (a is DefaultValueAttribute) |
||||
{ |
||||
defaultValues[displayName] = new PropertyDefaultValue(pi.PropertyType, |
||||
Convert.ChangeType((a as DefaultValueAttribute).Value, pi.PropertyType, CultureInfo.CurrentCulture)); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
internal struct PropertyDefaultValue |
||||
{ |
||||
public PropertyDefaultValue(Type t, object v) |
||||
{ |
||||
Type = t; |
||||
DefaultValue = v; |
||||
} |
||||
|
||||
public Type Type; |
||||
public object DefaultValue; |
||||
} |
||||
|
||||
internal class ValidKeywordsAttribute : Attribute |
||||
{ |
||||
private string keywords; |
||||
|
||||
public ValidKeywordsAttribute(string keywords) |
||||
{ |
||||
this.keywords = keywords.ToLower(CultureInfo.InvariantCulture); |
||||
} |
||||
|
||||
public string[] Keywords |
||||
{ |
||||
get { return keywords.Split(','); } |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,351 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Collection of error codes that can be returned by the server |
||||
/// </summary> |
||||
public class MySqlError |
||||
{ |
||||
private string level; |
||||
private int code; |
||||
private string message; |
||||
|
||||
/// <summary></summary> |
||||
/// <param name="level"></param> |
||||
/// <param name="code"></param> |
||||
/// <param name="message"></param> |
||||
public MySqlError(string level, int code, string message) |
||||
{ |
||||
this.level = level; |
||||
this.code = code; |
||||
this.message = message; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Error level |
||||
/// </summary> |
||||
public string Level |
||||
{ |
||||
get { return level; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Error code |
||||
/// </summary> |
||||
public int Code |
||||
{ |
||||
get { return code; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Error message |
||||
/// </summary> |
||||
public string Message |
||||
{ |
||||
get { return message; } |
||||
} |
||||
}; |
||||
|
||||
/// <summary> |
||||
/// Provides a reference to error codes returned by MySQL. |
||||
/// </summary> |
||||
public enum MySqlErrorCode |
||||
{ |
||||
None = 0, |
||||
/* ER_HASHCHK=1000, |
||||
ER_NISAMCHK=1001, |
||||
ER_NO=1002, |
||||
ER_YES 1003 |
||||
ER_CANT_CREATE_FILE 1004 |
||||
ER_CANT_CREATE_TABLE 1005 |
||||
ER_CANT_CREATE_DB 1006 |
||||
ER_DB_CREATE_EXISTS 1007 |
||||
ER_DB_DROP_EXISTS 1008 |
||||
ER_DB_DROP_DELETE 1009 |
||||
ER_DB_DROP_RMDIR 1010 |
||||
ER_CANT_DELETE_FILE 1011 |
||||
ER_CANT_FIND_SYSTEM_REC 1012 |
||||
ER_CANT_GET_STAT 1013 |
||||
ER_CANT_GET_WD 1014 |
||||
ER_CANT_LOCK 1015 |
||||
ER_CANT_OPEN_FILE 1016 |
||||
ER_FILE_NOT_FOUND 1017 |
||||
ER_CANT_READ_DIR 1018 |
||||
ER_CANT_SET_WD 1019 |
||||
ER_CHECKREAD 1020 |
||||
ER_DISK_FULL 1021 |
||||
*/ |
||||
/// <summary> |
||||
/// There is already a key with the given values. |
||||
/// </summary> |
||||
DuplicateKey = 1022, |
||||
|
||||
/* ER_ERROR_ON_CLOSE 1023 |
||||
ER_ERROR_ON_READ 1024 |
||||
ER_ERROR_ON_RENAME 1025 |
||||
ER_ERROR_ON_WRITE 1026 |
||||
ER_FILE_USED 1027 |
||||
ER_FILSORT_ABORT 1028 |
||||
ER_FORM_NOT_FOUND 1029 |
||||
ER_GET_ERRNO 1030 |
||||
ER_ILLEGAL_HA 1031*/ |
||||
/// <summary> |
||||
/// The specified key was not found. |
||||
/// </summary> |
||||
KeyNotFound = 1032, |
||||
/* ER_NOT_FORM_FILE 1033 |
||||
ER_NOT_KEYFILE 1034 |
||||
ER_OLD_KEYFILE 1035 |
||||
ER_OPEN_AS_READONLY 1036 |
||||
ER_OUTOFMEMORY 1037 |
||||
ER_OUT_OF_SORTMEMORY 1038 |
||||
ER_UNEXPECTED_EOF 1039 |
||||
ER_CON_COUNT_ERROR 1040 |
||||
ER_OUT_OF_RESOURCES 1041*/ |
||||
/// <summary> |
||||
/// Given when the connection is unable to successfully connect to host. |
||||
/// </summary> |
||||
UnableToConnectToHost = 1042, |
||||
/* ER_HANDSHAKE_ERROR 1043 |
||||
ER_DBACCESS_DENIED_ERROR 1044*/ |
||||
/// <summary> |
||||
/// Normally returned when an incorrect password is given |
||||
/// </summary> |
||||
AccessDenied = 1045, |
||||
/* ER_NO_DB_ERROR 1046 |
||||
ER_UNKNOWN_COM_ERROR 1047 |
||||
ER_BAD_NULL_ERROR 1048*/ |
||||
UnknownDatabase = 1049, |
||||
/*ER_BAD_DB_ERROR 1049 |
||||
ER_TABLE_EXISTS_ERROR 1050 |
||||
ER_BAD_TABLE_ERROR 1051 |
||||
ER_NON_UNIQ_ERROR 1052 |
||||
ER_SERVER_SHUTDOWN 1053 |
||||
ER_BAD_FIELD_ERROR 1054 |
||||
ER_WRONG_FIELD_WITH_GROUP 1055 |
||||
ER_WRONG_GROUP_FIELD 1056 |
||||
ER_WRONG_SUM_SELECT 1057 |
||||
ER_WRONG_VALUE_COUNT 1058 |
||||
ER_TOO_LONG_IDENT 1059 |
||||
ER_DUP_FIELDNAME 1060*/ |
||||
/// <summary> |
||||
/// Duplicate Key Name |
||||
/// </summary> |
||||
DuplicateKeyName = 1061, |
||||
/// <summary> |
||||
/// Duplicate Key Entry |
||||
/// </summary> |
||||
DuplicateKeyEntry = 1062, |
||||
|
||||
/* ER_WRONG_FIELD_SPEC 1063 |
||||
ER_PARSE_ERROR 1064 |
||||
ER_EMPTY_QUERY 1065 |
||||
ER_NONUNIQ_TABLE 1066 |
||||
ER_INVALID_DEFAULT 1067 |
||||
ER_MULTIPLE_PRI_KEY 1068 |
||||
ER_TOO_MANY_KEYS 1069 |
||||
ER_TOO_MANY_KEY_PARTS 1070 |
||||
ER_TOO_LONG_KEY 1071 |
||||
ER_KEY_COLUMN_DOES_NOT_EXITS 1072 |
||||
ER_BLOB_USED_AS_KEY 1073 |
||||
ER_TOO_BIG_FIELDLENGTH 1074 |
||||
ER_WRONG_AUTO_KEY 1075 |
||||
ER_READY 1076 |
||||
ER_NORMAL_SHUTDOWN 1077 |
||||
ER_GOT_SIGNAL 1078 |
||||
ER_SHUTDOWN_COMPLETE 1079 |
||||
ER_FORCING_CLOSE 1080 |
||||
ER_IPSOCK_ERROR 1081 |
||||
ER_NO_SUCH_INDEX 1082 |
||||
ER_WRONG_FIELD_TERMINATORS 1083 |
||||
ER_BLOBS_AND_NO_TERMINATED 1084 |
||||
ER_TEXTFILE_NOT_READABLE 1085 |
||||
ER_FILE_EXISTS_ERROR 1086 |
||||
ER_LOAD_INFO 1087 |
||||
ER_ALTER_INFO 1088 |
||||
ER_WRONG_SUB_KEY 1089 |
||||
ER_CANT_REMOVE_ALL_FIELDS 1090 |
||||
ER_CANT_DROP_FIELD_OR_KEY 1091 |
||||
ER_INSERT_INFO 1092 |
||||
ER_INSERT_TABLE_USED 1093 |
||||
ER_NO_SUCH_THREAD 1094 |
||||
ER_KILL_DENIED_ERROR 1095 |
||||
ER_NO_TABLES_USED 1096 |
||||
ER_TOO_BIG_SET 1097 |
||||
ER_NO_UNIQUE_LOGFILE 1098 |
||||
ER_TABLE_NOT_LOCKED_FOR_WRITE 1099 |
||||
ER_TABLE_NOT_LOCKED 1100 |
||||
ER_BLOB_CANT_HAVE_DEFAULT 1101 |
||||
ER_WRONG_DB_NAME 1102 |
||||
ER_WRONG_TABLE_NAME 1103 |
||||
ER_TOO_BIG_SELECT 1104 |
||||
ER_UNKNOWN_ERROR 1105 |
||||
ER_UNKNOWN_PROCEDURE 1106 |
||||
ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107 |
||||
ER_WRONG_PARAMETERS_TO_PROCEDURE 1108 |
||||
ER_UNKNOWN_TABLE 1109 |
||||
ER_FIELD_SPECIFIED_TWICE 1110 |
||||
ER_INVALID_GROUP_FUNC_USE 1111 |
||||
ER_UNSUPPORTED_EXTENSION 1112 |
||||
ER_TABLE_MUST_HAVE_COLUMNS 1113 |
||||
ER_RECORD_FILE_FULL 1114 |
||||
ER_UNKNOWN_CHARACTER_SET 1115 |
||||
ER_TOO_MANY_TABLES 1116 |
||||
ER_TOO_MANY_FIELDS 1117 |
||||
ER_TOO_BIG_ROWSIZE 1118 |
||||
ER_STACK_OVERRUN 1119 |
||||
ER_WRONG_OUTER_JOIN 1120 |
||||
ER_NULL_COLUMN_IN_INDEX 1121 |
||||
ER_CANT_FIND_UDF 1122 |
||||
ER_CANT_INITIALIZE_UDF 1123 |
||||
ER_UDF_NO_PATHS 1124 |
||||
ER_UDF_EXISTS 1125 |
||||
ER_CANT_OPEN_LIBRARY 1126 |
||||
ER_CANT_FIND_DL_ENTRY 1127 |
||||
ER_FUNCTION_NOT_DEFINED 1128 |
||||
ER_HOST_IS_BLOCKED 1129 |
||||
*/ |
||||
/// <summary> |
||||
/// The given host is not allowed to connect |
||||
/// </summary> |
||||
HostNotPrivileged = 1130, |
||||
/// <summary> |
||||
/// The anonymous user is not allowed to connect |
||||
/// </summary> |
||||
AnonymousUser = 1131, |
||||
/// <summary> |
||||
/// The given password is not allowed |
||||
/// </summary> |
||||
PasswordNotAllowed = 1132, |
||||
/// <summary> |
||||
/// The given password does not match |
||||
/// </summary> |
||||
PasswordNoMatch = 1133, |
||||
/* ER_UPDATE_INFO 1134 |
||||
ER_CANT_CREATE_THREAD 1135 |
||||
ER_WRONG_VALUE_COUNT_ON_ROW 1136 |
||||
ER_CANT_REOPEN_TABLE 1137 |
||||
ER_INVALID_USE_OF_NULL 1138 |
||||
ER_REGEXP_ERROR 1139 |
||||
ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140 |
||||
ER_NONEXISTING_GRANT 1141*/ TableAccessDenied = 1142, ColumnAccessDenied = 1143, IllegalGrantForTable = 1144,/* ER_GRANT_WRONG_HOST_OR_USER 1145 */ NoSuchTable = 1146, |
||||
NonExistingTableGrant = 1147, |
||||
|
||||
/* ER_NOT_ALLOWED_COMMAND 1148 |
||||
ER_SYNTAX_ERROR 1149 |
||||
ER_DELAYED_CANT_CHANGE_LOCK 1150 |
||||
ER_TOO_MANY_DELAYED_THREADS 1151 |
||||
ER_ABORTING_CONNECTION 1152 |
||||
*/ |
||||
/// <summary> |
||||
/// An attempt was made to send or receive a packet larger than |
||||
/// max_allowed_packet_size |
||||
/// </summary> |
||||
PacketTooLarge=1153 |
||||
/* |
||||
ER_NET_READ_ERROR_FROM_PIPE 1154 |
||||
ER_NET_FCNTL_ERROR 1155 |
||||
ER_NET_PACKETS_OUT_OF_ORDER 1156 |
||||
ER_NET_UNCOMPRESS_ERROR 1157 |
||||
ER_NET_READ_ERROR 1158 |
||||
ER_NET_READ_INTERRUPTED 1159 |
||||
ER_NET_ERROR_ON_WRITE 1160 |
||||
ER_NET_WRITE_INTERRUPTED 1161 |
||||
ER_TOO_LONG_STRING 1162 |
||||
ER_TABLE_CANT_HANDLE_BLOB 1163 |
||||
ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164 |
||||
ER_DELAYED_INSERT_TABLE_LOCKED 1165 |
||||
ER_WRONG_COLUMN_NAME 1166 |
||||
ER_WRONG_KEY_COLUMN 1167 |
||||
ER_WRONG_MRG_TABLE 1168 |
||||
ER_DUP_UNIQUE 1169 |
||||
ER_BLOB_KEY_WITHOUT_LENGTH 1170 |
||||
ER_PRIMARY_CANT_HAVE_NULL 1171 |
||||
ER_TOO_MANY_ROWS 1172 |
||||
ER_REQUIRES_PRIMARY_KEY 1173 |
||||
ER_NO_RAID_COMPILED 1174 |
||||
ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175 |
||||
ER_KEY_DOES_NOT_EXITS 1176 |
||||
ER_CHECK_NO_SUCH_TABLE 1177 |
||||
ER_CHECK_NOT_IMPLEMENTED 1178 |
||||
ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 |
||||
ER_ERROR_DURING_COMMIT 1180 |
||||
ER_ERROR_DURING_ROLLBACK 1181 |
||||
ER_ERROR_DURING_FLUSH_LOGS 1182 |
||||
ER_ERROR_DURING_CHECKPOINT 1183 |
||||
ER_NEW_ABORTING_CONNECTION 1184 |
||||
ER_DUMP_NOT_IMPLEMENTED 1185 |
||||
ER_FLUSH_MASTER_BINLOG_CLOSED 1186 |
||||
ER_INDEX_REBUILD 1187 |
||||
ER_MASTER 1188 |
||||
ER_MASTER_NET_READ 1189 |
||||
ER_MASTER_NET_WRITE 1190 |
||||
ER_FT_MATCHING_KEY_NOT_FOUND 1191 |
||||
ER_LOCK_OR_ACTIVE_TRANSACTION 1192 |
||||
ER_UNKNOWN_SYSTEM_VARIABLE 1193 |
||||
ER_CRASHED_ON_USAGE 1194 |
||||
ER_CRASHED_ON_REPAIR 1195 |
||||
ER_WARNING_NOT_COMPLETE_ROLLBACK 1196 |
||||
ER_TRANS_CACHE_FULL 1197 |
||||
ER_SLAVE_MUST_STOP 1198 |
||||
ER_SLAVE_NOT_RUNNING 1199 |
||||
ER_BAD_SLAVE 1200 |
||||
ER_MASTER_INFO 1201 |
||||
ER_SLAVE_THREAD 1202 |
||||
ER_TOO_MANY_USER_CONNECTIONS 1203 |
||||
ER_SET_CONSTANTS_ONLY 1204 |
||||
ER_LOCK_WAIT_TIMEOUT 1205 |
||||
ER_LOCK_TABLE_FULL 1206 |
||||
ER_READ_ONLY_TRANSACTION 1207 |
||||
ER_DROP_DB_WITH_READ_LOCK 1208 |
||||
ER_CREATE_DB_WITH_READ_LOCK 1209 |
||||
ER_WRONG_ARGUMENTS 1210 |
||||
ER_NO_PERMISSION_TO_CREATE_USER 1211 |
||||
ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 |
||||
ER_LOCK_DEADLOCK 1213 |
||||
ER_TABLE_CANT_HANDLE_FULLTEXT 1214 |
||||
ER_CANNOT_ADD_FOREIGN 1215 |
||||
ER_NO_REFERENCED_ROW 1216 |
||||
ER_ROW_IS_REFERENCED 1217 |
||||
ER_CONNECT_TO_MASTER 1218 |
||||
ER_QUERY_ON_MASTER 1219 |
||||
ER_ERROR_WHEN_EXECUTING_COMMAND 1220 |
||||
ER_WRONG_USAGE 1221 |
||||
ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222 |
||||
ER_CANT_UPDATE_WITH_READLOCK 1223 |
||||
ER_MIXING_NOT_ALLOWED 1224 |
||||
ER_DUP_ARGUMENT 1225 |
||||
ER_USER_LIMIT_REACHED 1226 |
||||
ER_SPECIFIC_ACCESS_DENIED_ERROR 1227 |
||||
ER_LOCAL_VARIABLE 1228 |
||||
ER_GLOBAL_VARIABLE 1229 |
||||
ER_NO_DEFAULT 1230 |
||||
ER_WRONG_VALUE_FOR_VAR 1231 |
||||
ER_WRONG_TYPE_FOR_VAR 1232 |
||||
ER_VAR_CANT_BE_READ 1233 |
||||
ER_CANT_USE_OPTION_HERE 1234 |
||||
ER_NOT_SUPPORTED_YET 1235 |
||||
ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 |
||||
ER_SLAVE_IGNORED_TABLE 1237 // only the slave SQL thread can be sent this |
||||
ER_ERROR_MESSAGES 238*/ |
||||
} |
||||
} |
@ -0,0 +1,406 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Text; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Helper class that makes it easier to work with the provider. |
||||
/// </summary> |
||||
public sealed class MySqlHelper |
||||
{ |
||||
private static string stringOfBackslashChars = "\u005c\u00a5\u0160\u20a9\u2216\ufe68\uff3c"; |
||||
private static string stringOfQuoteChars = |
||||
"\u0027\u0060\u00b4\u02b9\u02ba\u02bb\u02bc\u02c8\u02ca\u02cb\u02d9\u0300\u0301\u2018\u2019\u201a\u2032\u2035\u275b\u275c\uff07"; |
||||
|
||||
// this class provides only static methods |
||||
private MySqlHelper() |
||||
{ |
||||
} |
||||
|
||||
#region ExecuteNonQuery |
||||
|
||||
/// <summary> |
||||
/// Executes a single command against a MySQL database. The <see cref="MySqlConnection"/> is assumed to be |
||||
/// open when the method is called and remains open after the method completes. |
||||
/// </summary> |
||||
/// <param name="connection"><see cref="MySqlConnection"/> object to use</param> |
||||
/// <param name="commandText">SQL command to be executed</param> |
||||
/// <param name="commandParameters">Array of <see cref="MySqlParameter"/> objects to use with the command.</param> |
||||
/// <returns></returns> |
||||
public static int ExecuteNonQuery( MySqlConnection connection, string commandText, params MySqlParameter[] commandParameters ) |
||||
{ |
||||
//create a command and prepare it for execution |
||||
MySqlCommand cmd = new MySqlCommand(); |
||||
cmd.Connection = connection; |
||||
cmd.CommandText = commandText; |
||||
cmd.CommandType = CommandType.Text; |
||||
|
||||
if (commandParameters != null) |
||||
foreach (MySqlParameter p in commandParameters) |
||||
cmd.Parameters.Add( p ); |
||||
|
||||
int result = cmd.ExecuteNonQuery(); |
||||
cmd.Parameters.Clear(); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Executes a single command against a MySQL database. A new <see cref="MySqlConnection"/> is created |
||||
/// using the <see cref="MySqlConnection.ConnectionString"/> given. |
||||
/// </summary> |
||||
/// <param name="connectionString"><see cref="MySqlConnection.ConnectionString"/> to use</param> |
||||
/// <param name="commandText">SQL command to be executed</param> |
||||
/// <param name="parms">Array of <see cref="MySqlParameter"/> objects to use with the command.</param> |
||||
/// <returns></returns> |
||||
public static int ExecuteNonQuery( string connectionString, string commandText, params MySqlParameter[] parms ) |
||||
{ |
||||
//create & open a SqlConnection, and dispose of it after we are done. |
||||
using (MySqlConnection cn = new MySqlConnection(connectionString)) |
||||
{ |
||||
cn.Open(); |
||||
|
||||
//call the overload that takes a connection in place of the connection string |
||||
return ExecuteNonQuery(cn, commandText, parms ); |
||||
} |
||||
} |
||||
#endregion |
||||
|
||||
#region ExecuteDataSet |
||||
|
||||
/// <summary> |
||||
/// Executes a single SQL command and returns the first row of the resultset. A new MySqlConnection object |
||||
/// is created, opened, and closed during this method. |
||||
/// </summary> |
||||
/// <param name="connectionString">Settings to be used for the connection</param> |
||||
/// <param name="commandText">Command to execute</param> |
||||
/// <param name="parms">Parameters to use for the command</param> |
||||
/// <returns>DataRow containing the first row of the resultset</returns> |
||||
public static DataRow ExecuteDataRow( string connectionString, string commandText, params MySqlParameter[] parms ) |
||||
{ |
||||
DataSet ds = ExecuteDataset( connectionString, commandText, parms ); |
||||
if (ds == null) return null; |
||||
if (ds.Tables.Count == 0) return null; |
||||
if (ds.Tables[0].Rows.Count == 0) return null; |
||||
return ds.Tables[0].Rows[0]; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Executes a single SQL command and returns the resultset in a <see cref="DataSet"/>. |
||||
/// A new MySqlConnection object is created, opened, and closed during this method. |
||||
/// </summary> |
||||
/// <param name="connectionString">Settings to be used for the connection</param> |
||||
/// <param name="commandText">Command to execute</param> |
||||
/// <returns><see cref="DataSet"/> containing the resultset</returns> |
||||
public static DataSet ExecuteDataset(string connectionString, string commandText) |
||||
{ |
||||
//pass through the call providing null for the set of SqlParameters |
||||
return ExecuteDataset(connectionString, commandText, (MySqlParameter[])null); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Executes a single SQL command and returns the resultset in a <see cref="DataSet"/>. |
||||
/// A new MySqlConnection object is created, opened, and closed during this method. |
||||
/// </summary> |
||||
/// <param name="connectionString">Settings to be used for the connection</param> |
||||
/// <param name="commandText">Command to execute</param> |
||||
/// <param name="commandParameters">Parameters to use for the command</param> |
||||
/// <returns><see cref="DataSet"/> containing the resultset</returns> |
||||
public static DataSet ExecuteDataset(string connectionString, string commandText, params MySqlParameter[] commandParameters) |
||||
{ |
||||
//create & open a SqlConnection, and dispose of it after we are done. |
||||
using (MySqlConnection cn = new MySqlConnection(connectionString)) |
||||
{ |
||||
cn.Open(); |
||||
|
||||
//call the overload that takes a connection in place of the connection string |
||||
return ExecuteDataset(cn, commandText, commandParameters); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Executes a single SQL command and returns the resultset in a <see cref="DataSet"/>. |
||||
/// The state of the <see cref="MySqlConnection"/> object remains unchanged after execution |
||||
/// of this method. |
||||
/// </summary> |
||||
/// <param name="connection"><see cref="MySqlConnection"/> object to use</param> |
||||
/// <param name="commandText">Command to execute</param> |
||||
/// <returns><see cref="DataSet"/> containing the resultset</returns> |
||||
public static DataSet ExecuteDataset(MySqlConnection connection, string commandText) |
||||
{ |
||||
//pass through the call providing null for the set of SqlParameters |
||||
return ExecuteDataset(connection, commandText, (MySqlParameter[])null); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Executes a single SQL command and returns the resultset in a <see cref="DataSet"/>. |
||||
/// The state of the <see cref="MySqlConnection"/> object remains unchanged after execution |
||||
/// of this method. |
||||
/// </summary> |
||||
/// <param name="connection"><see cref="MySqlConnection"/> object to use</param> |
||||
/// <param name="commandText">Command to execute</param> |
||||
/// <param name="commandParameters">Parameters to use for the command</param> |
||||
/// <returns><see cref="DataSet"/> containing the resultset</returns> |
||||
public static DataSet ExecuteDataset(MySqlConnection connection, string commandText, params MySqlParameter[] commandParameters) |
||||
{ |
||||
//create a command and prepare it for execution |
||||
MySqlCommand cmd = new MySqlCommand(); |
||||
cmd.Connection = connection; |
||||
cmd.CommandText = commandText; |
||||
cmd.CommandType = CommandType.Text; |
||||
|
||||
if (commandParameters != null) |
||||
foreach (MySqlParameter p in commandParameters) |
||||
cmd.Parameters.Add( p ); |
||||
|
||||
//create the DataAdapter & DataSet |
||||
MySqlDataAdapter da = new MySqlDataAdapter(cmd); |
||||
DataSet ds = new DataSet(); |
||||
|
||||
//fill the DataSet using default values for DataTable names, etc. |
||||
da.Fill(ds); |
||||
|
||||
// detach the MySqlParameters from the command object, so they can be used again. |
||||
cmd.Parameters.Clear(); |
||||
|
||||
//return the dataset |
||||
return ds; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Updates the given table with data from the given <see cref="DataSet"/> |
||||
/// </summary> |
||||
/// <param name="connectionString">Settings to use for the update</param> |
||||
/// <param name="commandText">Command text to use for the update</param> |
||||
/// <param name="ds"><see cref="DataSet"/> containing the new data to use in the update</param> |
||||
/// <param name="tablename">Tablename in the dataset to update</param> |
||||
public static void UpdateDataSet( string connectionString, string commandText, DataSet ds, string tablename ) |
||||
{ |
||||
MySqlConnection cn = new MySqlConnection( connectionString ); |
||||
cn.Open(); |
||||
MySqlDataAdapter da = new MySqlDataAdapter( commandText, cn ); |
||||
MySqlCommandBuilder cb = new MySqlCommandBuilder(da); |
||||
cb.ToString(); |
||||
da.Update( ds, tablename ); |
||||
cn.Close(); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region ExecuteDataReader |
||||
|
||||
/// <summary> |
||||
/// Executes a single command against a MySQL database, possibly inside an existing transaction. |
||||
/// </summary> |
||||
/// <param name="connection"><see cref="MySqlConnection"/> object to use for the command</param> |
||||
/// <param name="transaction"><see cref="MySqlTransaction"/> object to use for the command</param> |
||||
/// <param name="commandText">Command text to use</param> |
||||
/// <param name="commandParameters">Array of <see cref="MySqlParameter"/> objects to use with the command</param> |
||||
/// <param name="ExternalConn">True if the connection should be preserved, false if not</param> |
||||
/// <returns><see cref="MySqlDataReader"/> object ready to read the results of the command</returns> |
||||
private static MySqlDataReader ExecuteReader(MySqlConnection connection, MySqlTransaction transaction, string commandText, MySqlParameter[] commandParameters, bool ExternalConn ) |
||||
{ |
||||
//create a command and prepare it for execution |
||||
MySqlCommand cmd = new MySqlCommand(); |
||||
cmd.Connection = connection; |
||||
cmd.Transaction = transaction; |
||||
cmd.CommandText = commandText; |
||||
cmd.CommandType = CommandType.Text; |
||||
|
||||
if (commandParameters != null) |
||||
foreach (MySqlParameter p in commandParameters) |
||||
cmd.Parameters.Add( p ); |
||||
|
||||
//create a reader |
||||
MySqlDataReader dr; |
||||
|
||||
// call ExecuteReader with the appropriate CommandBehavior |
||||
if (ExternalConn) |
||||
{ |
||||
dr = cmd.ExecuteReader(); |
||||
} |
||||
else |
||||
{ |
||||
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); |
||||
} |
||||
|
||||
// detach the SqlParameters from the command object, so they can be used again. |
||||
cmd.Parameters.Clear(); |
||||
|
||||
return dr; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Executes a single command against a MySQL database. |
||||
/// </summary> |
||||
/// <param name="connectionString">Settings to use for this command</param> |
||||
/// <param name="commandText">Command text to use</param> |
||||
/// <returns><see cref="MySqlDataReader"/> object ready to read the results of the command</returns> |
||||
public static MySqlDataReader ExecuteReader(string connectionString, string commandText) |
||||
{ |
||||
//pass through the call providing null for the set of SqlParameters |
||||
return ExecuteReader(connectionString, commandText, (MySqlParameter[])null); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Executes a single command against a MySQL database. |
||||
/// </summary> |
||||
/// <param name="connectionString">Settings to use for this command</param> |
||||
/// <param name="commandText">Command text to use</param> |
||||
/// <param name="commandParameters">Array of <see cref="MySqlParameter"/> objects to use with the command</param> |
||||
/// <returns><see cref="MySqlDataReader"/> object ready to read the results of the command</returns> |
||||
public static MySqlDataReader ExecuteReader(string connectionString, string commandText, params MySqlParameter[] commandParameters) |
||||
{ |
||||
//create & open a SqlConnection |
||||
MySqlConnection cn = new MySqlConnection(connectionString); |
||||
cn.Open(); |
||||
|
||||
try |
||||
{ |
||||
//call the private overload that takes an internally owned connection in place of the connection string |
||||
return ExecuteReader(cn, null, commandText, commandParameters, false ); |
||||
} |
||||
catch |
||||
{ |
||||
//if we fail to return the SqlDatReader, we need to close the connection ourselves |
||||
cn.Close(); |
||||
throw; |
||||
} |
||||
} |
||||
#endregion |
||||
|
||||
#region ExecuteScalar |
||||
|
||||
/// <summary> |
||||
/// Execute a single command against a MySQL database. |
||||
/// </summary> |
||||
/// <param name="connectionString">Settings to use for the update</param> |
||||
/// <param name="commandText">Command text to use for the update</param> |
||||
/// <returns>The first column of the first row in the result set, or a null reference if the result set is empty.</returns> |
||||
public static object ExecuteScalar(string connectionString, string commandText) |
||||
{ |
||||
//pass through the call providing null for the set of MySqlParameters |
||||
return ExecuteScalar(connectionString, commandText, (MySqlParameter[])null); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Execute a single command against a MySQL database. |
||||
/// </summary> |
||||
/// <param name="connectionString">Settings to use for the command</param> |
||||
/// <param name="commandText">Command text to use for the command</param> |
||||
/// <param name="commandParameters">Parameters to use for the command</param> |
||||
/// <returns>The first column of the first row in the result set, or a null reference if the result set is empty.</returns> |
||||
public static object ExecuteScalar(string connectionString, string commandText, params MySqlParameter[] commandParameters) |
||||
{ |
||||
//create & open a SqlConnection, and dispose of it after we are done. |
||||
using (MySqlConnection cn = new MySqlConnection(connectionString)) |
||||
{ |
||||
cn.Open(); |
||||
|
||||
//call the overload that takes a connection in place of the connection string |
||||
return ExecuteScalar(cn, commandText, commandParameters); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Execute a single command against a MySQL database. |
||||
/// </summary> |
||||
/// <param name="connection"><see cref="MySqlConnection"/> object to use</param> |
||||
/// <param name="commandText">Command text to use for the command</param> |
||||
/// <returns>The first column of the first row in the result set, or a null reference if the result set is empty.</returns> |
||||
public static object ExecuteScalar(MySqlConnection connection, string commandText) |
||||
{ |
||||
//pass through the call providing null for the set of MySqlParameters |
||||
return ExecuteScalar(connection, commandText, (MySqlParameter[])null); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Execute a single command against a MySQL database. |
||||
/// </summary> |
||||
/// <param name="connection"><see cref="MySqlConnection"/> object to use</param> |
||||
/// <param name="commandText">Command text to use for the command</param> |
||||
/// <param name="commandParameters">Parameters to use for the command</param> |
||||
/// <returns>The first column of the first row in the result set, or a null reference if the result set is empty.</returns> |
||||
public static object ExecuteScalar(MySqlConnection connection, string commandText, params MySqlParameter[] commandParameters) |
||||
{ |
||||
//create a command and prepare it for execution |
||||
MySqlCommand cmd = new MySqlCommand(); |
||||
cmd.Connection = connection; |
||||
cmd.CommandText = commandText; |
||||
cmd.CommandType = CommandType.Text; |
||||
|
||||
if (commandParameters != null) |
||||
foreach (MySqlParameter p in commandParameters) |
||||
cmd.Parameters.Add( p ); |
||||
|
||||
//execute the command & return the results |
||||
object retval = cmd.ExecuteScalar(); |
||||
|
||||
// detach the SqlParameters from the command object, so they can be used again. |
||||
cmd.Parameters.Clear(); |
||||
return retval; |
||||
|
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Utility methods |
||||
|
||||
/// <summary> |
||||
/// Escapes the string. |
||||
/// </summary> |
||||
/// <param name="value">The string to escape</param> |
||||
/// <returns>The string with all quotes escaped.</returns> |
||||
public static string EscapeString(string value) |
||||
{ |
||||
StringBuilder sb = new StringBuilder(); |
||||
foreach (char c in value) |
||||
{ |
||||
if (stringOfQuoteChars.IndexOf(c) >= 0 || |
||||
//sb.Append(c); |
||||
//else if ( |
||||
stringOfBackslashChars.IndexOf(c) >= 0) |
||||
sb.Append("\\"); |
||||
sb.Append(c); |
||||
} |
||||
return sb.ToString(); |
||||
} |
||||
|
||||
public static string DoubleQuoteString(string value) |
||||
{ |
||||
StringBuilder sb = new StringBuilder(); |
||||
foreach (char c in value) |
||||
{ |
||||
if (stringOfQuoteChars.IndexOf(c) >= 0) |
||||
sb.Append(c); |
||||
else if (stringOfBackslashChars.IndexOf(c) >= 0) |
||||
sb.Append("\\"); |
||||
sb.Append(c); |
||||
} |
||||
return sb.ToString(); |
||||
} |
||||
|
||||
#endregion |
||||
} |
||||
} |
@ -0,0 +1,330 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.Threading; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
|
||||
|
||||
/// <summary> |
||||
/// Summary description for MySqlPool. |
||||
/// </summary> |
||||
internal sealed class MySqlPool |
||||
{ |
||||
private List<Driver> inUsePool; |
||||
private Queue<Driver> idlePool; |
||||
private MySqlConnectionStringBuilder settings; |
||||
private uint minSize; |
||||
private uint maxSize; |
||||
private ProcedureCache procedureCache; |
||||
private bool beingCleared; |
||||
private int available; |
||||
private AutoResetEvent autoEvent; |
||||
|
||||
private void EnqueueIdle(Driver driver) |
||||
{ |
||||
driver.IdleSince = DateTime.Now; |
||||
idlePool.Enqueue(driver); |
||||
} |
||||
public MySqlPool(MySqlConnectionStringBuilder settings) |
||||
{ |
||||
minSize = settings.MinimumPoolSize; |
||||
maxSize = settings.MaximumPoolSize; |
||||
|
||||
available = (int)maxSize; |
||||
autoEvent = new AutoResetEvent(false); |
||||
|
||||
if (minSize > maxSize) |
||||
minSize = maxSize; |
||||
this.settings = settings; |
||||
inUsePool = new List<Driver>((int)maxSize); |
||||
idlePool = new Queue<Driver>((int)maxSize); |
||||
|
||||
// prepopulate the idle pool to minSize |
||||
for (int i = 0; i < minSize; i++) |
||||
EnqueueIdle(CreateNewPooledConnection()); |
||||
|
||||
procedureCache = new ProcedureCache((int)settings.ProcedureCacheSize); |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public MySqlConnectionStringBuilder Settings |
||||
{ |
||||
get { return settings; } |
||||
set { settings = value; } |
||||
} |
||||
|
||||
public ProcedureCache ProcedureCache |
||||
{ |
||||
get { return procedureCache; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// It is assumed that this property will only be used from inside an active |
||||
/// lock. |
||||
/// </summary> |
||||
private bool HasIdleConnections |
||||
{ |
||||
get { return idlePool.Count > 0; } |
||||
} |
||||
|
||||
private int NumConnections |
||||
{ |
||||
get { return idlePool.Count + inUsePool.Count; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Indicates whether this pool is being cleared. |
||||
/// </summary> |
||||
public bool BeingCleared |
||||
{ |
||||
get { return beingCleared; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
/// <summary> |
||||
/// It is assumed that this method is only called from inside an active lock. |
||||
/// </summary> |
||||
private Driver GetPooledConnection() |
||||
{ |
||||
Driver driver = null; |
||||
|
||||
// if we don't have an idle connection but we have room for a new |
||||
// one, then create it here. |
||||
lock ((idlePool as ICollection).SyncRoot) |
||||
{ |
||||
if (HasIdleConnections) |
||||
driver = idlePool.Dequeue(); |
||||
} |
||||
|
||||
// Obey the connection timeout |
||||
if (driver != null) |
||||
{ |
||||
try |
||||
{ |
||||
driver.ResetTimeout((int)Settings.ConnectionTimeout * 1000); |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
driver.Close(); |
||||
driver = null; |
||||
} |
||||
} |
||||
|
||||
if (driver != null) |
||||
{ |
||||
// first check to see that the server is still alive |
||||
if (!driver.Ping()) |
||||
{ |
||||
driver.Close(); |
||||
driver = null; |
||||
} |
||||
else if (settings.ConnectionReset) |
||||
// if the user asks us to ping/reset pooled connections |
||||
// do so now |
||||
driver.Reset(); |
||||
} |
||||
if (driver == null) |
||||
driver = CreateNewPooledConnection(); |
||||
|
||||
Debug.Assert(driver != null); |
||||
lock ((inUsePool as ICollection).SyncRoot) |
||||
{ |
||||
inUsePool.Add(driver); |
||||
} |
||||
return driver; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// It is assumed that this method is only called from inside an active lock. |
||||
/// </summary> |
||||
private Driver CreateNewPooledConnection() |
||||
{ |
||||
Debug.Assert((maxSize - NumConnections) > 0, "Pool out of sync."); |
||||
|
||||
Driver driver = Driver.Create(settings); |
||||
driver.Pool = this; |
||||
return driver; |
||||
} |
||||
|
||||
public void ReleaseConnection(Driver driver) |
||||
{ |
||||
lock ((inUsePool as ICollection).SyncRoot) |
||||
{ |
||||
if (inUsePool.Contains(driver)) |
||||
inUsePool.Remove(driver); |
||||
} |
||||
|
||||
if (driver.ConnectionLifetimeExpired() || beingCleared) |
||||
{ |
||||
driver.Close(); |
||||
Debug.Assert(!idlePool.Contains(driver)); |
||||
} |
||||
else |
||||
{ |
||||
lock ((idlePool as ICollection).SyncRoot) |
||||
{ |
||||
EnqueueIdle(driver); |
||||
} |
||||
} |
||||
|
||||
Interlocked.Increment(ref available); |
||||
autoEvent.Set(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Removes a connection from the in use pool. The only situations where this method |
||||
/// would be called are when a connection that is in use gets some type of fatal exception |
||||
/// or when the connection is being returned to the pool and it's too old to be |
||||
/// returned. |
||||
/// </summary> |
||||
/// <param name="driver"></param> |
||||
public void RemoveConnection(Driver driver) |
||||
{ |
||||
lock ((inUsePool as ICollection).SyncRoot) |
||||
{ |
||||
if (inUsePool.Contains(driver)) |
||||
{ |
||||
inUsePool.Remove(driver); |
||||
Interlocked.Increment(ref available); |
||||
autoEvent.Set(); |
||||
} |
||||
} |
||||
|
||||
// if we are being cleared and we are out of connections then have |
||||
// the manager destroy us. |
||||
if (beingCleared && NumConnections == 0) |
||||
MySqlPoolManager.RemoveClearedPool(this); |
||||
} |
||||
|
||||
private Driver TryToGetDriver() |
||||
{ |
||||
int count = Interlocked.Decrement(ref available); |
||||
if (count < 0) |
||||
{ |
||||
Interlocked.Increment(ref available); |
||||
return null; |
||||
} |
||||
try |
||||
{ |
||||
Driver driver = GetPooledConnection(); |
||||
return driver; |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
MySqlTrace.LogError(-1, ex.Message); |
||||
Interlocked.Increment(ref available); |
||||
throw; |
||||
} |
||||
} |
||||
|
||||
public Driver GetConnection() |
||||
{ |
||||
int fullTimeOut = (int)settings.ConnectionTimeout * 1000; |
||||
int timeOut = fullTimeOut; |
||||
|
||||
DateTime start = DateTime.Now; |
||||
|
||||
while (timeOut > 0) |
||||
{ |
||||
Driver driver = TryToGetDriver(); |
||||
if (driver != null) return driver; |
||||
|
||||
// We have no tickets right now, lets wait for one. |
||||
if (!autoEvent.WaitOne(timeOut, false)) break; |
||||
timeOut = fullTimeOut - (int)DateTime.Now.Subtract(start).TotalMilliseconds; |
||||
} |
||||
throw new MySqlException(Resources.TimeoutGettingConnection); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Clears this pool of all idle connections and marks this pool and being cleared |
||||
/// so all other connections are closed when they are returned. |
||||
/// </summary> |
||||
internal void Clear() |
||||
{ |
||||
lock ((idlePool as ICollection).SyncRoot) |
||||
{ |
||||
// first, mark ourselves as being cleared |
||||
beingCleared = true; |
||||
|
||||
// then we remove all connections sitting in the idle pool |
||||
while (idlePool.Count > 0) |
||||
{ |
||||
Driver d = idlePool.Dequeue(); |
||||
d.Close(); |
||||
} |
||||
|
||||
// there is nothing left to do here. Now we just wait for all |
||||
// in use connections to be returned to the pool. When they are |
||||
// they will be closed. When the last one is closed, the pool will |
||||
// be destroyed. |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Remove expired drivers from the idle pool |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
/// <remarks> |
||||
/// Closing driver is a potentially lengthy operation involving network |
||||
/// IO. Therefore we do not close expired drivers while holding |
||||
/// idlePool.SyncRoot lock. We just remove the old drivers from the idle |
||||
/// queue and return them to the caller. The caller will need to close |
||||
/// them (or let GC close them) |
||||
/// </remarks> |
||||
internal List<Driver> RemoveOldIdleConnections() |
||||
{ |
||||
List<Driver> oldDrivers = new List<Driver>(); |
||||
DateTime now = DateTime.Now; |
||||
|
||||
lock ((idlePool as ICollection).SyncRoot) |
||||
{ |
||||
// The drivers appear to be ordered by their age, i.e it is |
||||
// sufficient to remove them until the first element is not |
||||
// too old. |
||||
while(idlePool.Count > minSize) |
||||
{ |
||||
Driver d = idlePool.Peek(); |
||||
DateTime expirationTime = d.IdleSince.Add( |
||||
new TimeSpan(0,0, MySqlPoolManager.maxConnectionIdleTime)); |
||||
if (expirationTime.CompareTo(now) < 0) |
||||
{ |
||||
oldDrivers.Add(d); |
||||
idlePool.Dequeue(); |
||||
} |
||||
else |
||||
{ |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
return oldDrivers; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,153 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System.Collections; |
||||
using System.Diagnostics; |
||||
using System.Collections.Generic; |
||||
using System.Threading; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for MySqlPoolManager. |
||||
/// </summary> |
||||
internal class MySqlPoolManager |
||||
{ |
||||
private static Hashtable pools = new Hashtable(); |
||||
private static List<MySqlPool> clearingPools = new List<MySqlPool>(); |
||||
|
||||
// Timeout in seconds, after which an unused (idle) connection |
||||
// should be closed. |
||||
static internal int maxConnectionIdleTime = 180; |
||||
|
||||
|
||||
private static Timer timer = new Timer(new TimerCallback(CleanIdleConnections), |
||||
null, maxConnectionIdleTime*1000, maxConnectionIdleTime*1000); |
||||
|
||||
public static MySqlPool GetPool(MySqlConnectionStringBuilder settings) |
||||
{ |
||||
string text = settings.ConnectionString; |
||||
|
||||
lock (pools.SyncRoot) |
||||
{ |
||||
MySqlPool pool = (pools[text] as MySqlPool); |
||||
|
||||
if (pool == null) |
||||
{ |
||||
pool = new MySqlPool(settings); |
||||
pools.Add(text, pool); |
||||
} |
||||
else |
||||
pool.Settings = settings; |
||||
|
||||
return pool; |
||||
} |
||||
} |
||||
|
||||
public static void RemoveConnection(Driver driver) |
||||
{ |
||||
Debug.Assert(driver != null); |
||||
|
||||
MySqlPool pool = driver.Pool; |
||||
if (pool == null) return; |
||||
|
||||
pool.RemoveConnection(driver); |
||||
} |
||||
|
||||
public static void ReleaseConnection(Driver driver) |
||||
{ |
||||
Debug.Assert(driver != null); |
||||
|
||||
MySqlPool pool = driver.Pool; |
||||
if (pool == null) return; |
||||
|
||||
pool.ReleaseConnection(driver); |
||||
} |
||||
|
||||
public static void ClearPool(MySqlConnectionStringBuilder settings) |
||||
{ |
||||
Debug.Assert(settings != null); |
||||
|
||||
string text = settings.ConnectionString; |
||||
ClearPoolByText(text); |
||||
} |
||||
|
||||
private static void ClearPoolByText(string key) |
||||
{ |
||||
lock (pools.SyncRoot) |
||||
{ |
||||
// if pools doesn't have it, then this pool must already have been cleared |
||||
if (!pools.ContainsKey(key)) return; |
||||
|
||||
// add the pool to our list of pools being cleared |
||||
MySqlPool pool = (pools[key] as MySqlPool); |
||||
clearingPools.Add(pool); |
||||
|
||||
// now tell the pool to clear itself |
||||
pool.Clear(); |
||||
|
||||
// and then remove the pool from the active pools list |
||||
pools.Remove(key); |
||||
} |
||||
} |
||||
|
||||
public static void ClearAllPools() |
||||
{ |
||||
lock (pools.SyncRoot) |
||||
{ |
||||
// Create separate keys list. |
||||
List<string> keys = new List<string>(pools.Count); |
||||
|
||||
foreach (string key in pools.Keys) |
||||
keys.Add(key); |
||||
|
||||
// Remove all pools by key. |
||||
foreach (string key in keys) |
||||
ClearPoolByText(key); |
||||
} |
||||
} |
||||
|
||||
public static void RemoveClearedPool(MySqlPool pool) |
||||
{ |
||||
Debug.Assert(clearingPools.Contains(pool)); |
||||
clearingPools.Remove(pool); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Remove drivers that have been idle for too long. |
||||
/// </summary> |
||||
public static void CleanIdleConnections(object obj) |
||||
{ |
||||
List<Driver> oldDrivers = new List<Driver>(); |
||||
lock (pools.SyncRoot) |
||||
{ |
||||
foreach (string key in pools.Keys) |
||||
{ |
||||
MySqlPool pool = (pools[key] as MySqlPool); |
||||
oldDrivers.AddRange(pool.RemoveOldIdleConnections()); |
||||
} |
||||
} |
||||
foreach(Driver driver in oldDrivers) |
||||
{ |
||||
driver.Close(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,125 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Transactions; |
||||
using System.Collections; |
||||
using System.Data; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
internal sealed class MySqlPromotableTransaction : IPromotableSinglePhaseNotification, ITransactionPromoter |
||||
{ |
||||
private MySqlConnection connection; |
||||
private Transaction baseTransaction; |
||||
private MySqlTransaction simpleTransaction; |
||||
|
||||
public MySqlPromotableTransaction(MySqlConnection connection, Transaction baseTransaction) |
||||
{ |
||||
this.connection = connection; |
||||
this.baseTransaction = baseTransaction; |
||||
} |
||||
|
||||
public Transaction BaseTransaction |
||||
{ |
||||
get { return baseTransaction; } |
||||
} |
||||
|
||||
void IPromotableSinglePhaseNotification.Initialize() |
||||
{ |
||||
string valueName = Enum.GetName( |
||||
typeof(System.Transactions.IsolationLevel), baseTransaction.IsolationLevel); |
||||
System.Data.IsolationLevel dataLevel = (System.Data.IsolationLevel)Enum.Parse( |
||||
typeof(System.Data.IsolationLevel), valueName); |
||||
simpleTransaction = connection.BeginTransaction(dataLevel); |
||||
} |
||||
|
||||
void IPromotableSinglePhaseNotification.Rollback(SinglePhaseEnlistment singlePhaseEnlistment) |
||||
{ |
||||
// prevent commands in main thread to run concurrently |
||||
Driver driver = connection.driver; |
||||
lock (driver) |
||||
{ |
||||
while (connection.Reader != null) |
||||
{ |
||||
// wait for reader to finish. Maybe we should not wait |
||||
// forever and cancel it after some time? |
||||
System.Threading.Thread.Sleep(100); |
||||
} |
||||
simpleTransaction.Rollback(); |
||||
singlePhaseEnlistment.Aborted(); |
||||
DriverTransactionManager.RemoveDriverInTransaction(baseTransaction); |
||||
|
||||
driver.CurrentTransaction = null; |
||||
|
||||
if (connection.State == ConnectionState.Closed) |
||||
connection.CloseFully(); |
||||
} |
||||
} |
||||
|
||||
void IPromotableSinglePhaseNotification.SinglePhaseCommit(SinglePhaseEnlistment singlePhaseEnlistment) |
||||
{ |
||||
simpleTransaction.Commit(); |
||||
singlePhaseEnlistment.Committed(); |
||||
DriverTransactionManager.RemoveDriverInTransaction(baseTransaction); |
||||
|
||||
connection.driver.CurrentTransaction = null; |
||||
|
||||
if (connection.State == ConnectionState.Closed) |
||||
connection.CloseFully(); |
||||
} |
||||
|
||||
byte[] ITransactionPromoter.Promote() |
||||
{ |
||||
throw new NotSupportedException(); |
||||
} |
||||
} |
||||
|
||||
internal class DriverTransactionManager |
||||
{ |
||||
private static Hashtable driversInUse = new Hashtable(); |
||||
|
||||
public static Driver GetDriverInTransaction(Transaction transaction) |
||||
{ |
||||
lock (driversInUse.SyncRoot) |
||||
{ |
||||
Driver d = (Driver)driversInUse[transaction.GetHashCode()]; |
||||
return d; |
||||
} |
||||
} |
||||
|
||||
public static void SetDriverInTransaction(Driver driver) |
||||
{ |
||||
lock (driversInUse.SyncRoot) |
||||
{ |
||||
driversInUse[driver.CurrentTransaction.BaseTransaction.GetHashCode()] = driver; |
||||
} |
||||
} |
||||
|
||||
public static void RemoveDriverInTransaction(Transaction transaction) |
||||
{ |
||||
lock (driversInUse.SyncRoot) |
||||
{ |
||||
driversInUse.Remove(transaction.GetHashCode()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,433 @@ |
||||
// Copyright (c) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using MySql.Data.Common; |
||||
using System.Collections.Generic; |
||||
using System.Text; |
||||
using System; |
||||
using System.Data; |
||||
using System.Globalization; |
||||
using System.IO; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Provides a class capable of executing a SQL script containing |
||||
/// multiple SQL statements including CREATE PROCEDURE statements |
||||
/// that require changing the delimiter |
||||
/// </summary> |
||||
public class MySqlScript |
||||
{ |
||||
private MySqlConnection connection; |
||||
private string query; |
||||
private string delimiter; |
||||
|
||||
public event MySqlStatementExecutedEventHandler StatementExecuted; |
||||
public event MySqlScriptErrorEventHandler Error; |
||||
public event EventHandler ScriptCompleted; |
||||
|
||||
#region Constructors |
||||
|
||||
/// <summary> |
||||
/// Initializes a new instance of the |
||||
/// <see cref="MySqlScript"/> class. |
||||
/// </summary> |
||||
public MySqlScript() |
||||
{ |
||||
Delimiter = ";"; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initializes a new instance of the |
||||
/// <see cref="MySqlScript"/> class. |
||||
/// </summary> |
||||
/// <param name="connection">The connection.</param> |
||||
public MySqlScript(MySqlConnection connection) : this() |
||||
{ |
||||
this.connection = connection; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initializes a new instance of the |
||||
/// <see cref="MySqlScript"/> class. |
||||
/// </summary> |
||||
/// <param name="query">The query.</param> |
||||
public MySqlScript(string query) : this() |
||||
{ |
||||
this.query = query; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initializes a new instance of the |
||||
/// <see cref="MySqlScript"/> class. |
||||
/// </summary> |
||||
/// <param name="connection">The connection.</param> |
||||
/// <param name="query">The query.</param> |
||||
public MySqlScript(MySqlConnection connection, string query) |
||||
:this() |
||||
{ |
||||
this.connection = connection; |
||||
this.query = query; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Properties |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the connection. |
||||
/// </summary> |
||||
/// <value>The connection.</value> |
||||
public MySqlConnection Connection |
||||
{ |
||||
get { return connection; } |
||||
set { connection = value; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the query. |
||||
/// </summary> |
||||
/// <value>The query.</value> |
||||
public string Query |
||||
{ |
||||
get { return query; } |
||||
set { query = value; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the delimiter. |
||||
/// </summary> |
||||
/// <value>The delimiter.</value> |
||||
public string Delimiter |
||||
{ |
||||
get { return delimiter; } |
||||
set { delimiter = value; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Public Methods |
||||
|
||||
/// <summary> |
||||
/// Executes this instance. |
||||
/// </summary> |
||||
/// <returns>The number of statements executed as part of the script.</returns> |
||||
public int Execute() |
||||
{ |
||||
bool openedConnection = false; |
||||
|
||||
if (connection == null) |
||||
throw new InvalidOperationException(Resources.ConnectionNotSet); |
||||
if (query == null || query.Length == 0) |
||||
return 0; |
||||
|
||||
// next we open up the connetion if it is not already open |
||||
if (connection.State != ConnectionState.Open) |
||||
{ |
||||
openedConnection = true; |
||||
connection.Open(); |
||||
} |
||||
|
||||
// since we don't allow setting of parameters on a script we can |
||||
// therefore safely allow the use of user variables. no one should be using |
||||
// this connection while we are using it so we can temporarily tell it |
||||
// to allow the use of user variables |
||||
bool allowUserVars = connection.Settings.AllowUserVariables; |
||||
connection.Settings.AllowUserVariables = true; |
||||
|
||||
try |
||||
{ |
||||
string mode = connection.driver.Property("sql_mode"); |
||||
mode = mode.ToUpper(CultureInfo.InvariantCulture); |
||||
bool ansiQuotes = mode.IndexOf("ANSI_QUOTES") != -1; |
||||
bool noBackslashEscapes = mode.IndexOf("NO_BACKSLASH_ESCAPES") != -1; |
||||
|
||||
// first we break the query up into smaller queries |
||||
List<ScriptStatement> statements = BreakIntoStatements(ansiQuotes, noBackslashEscapes); |
||||
|
||||
int count = 0; |
||||
MySqlCommand cmd = new MySqlCommand(null, connection); |
||||
foreach (ScriptStatement statement in statements) |
||||
{ |
||||
if (String.IsNullOrEmpty(statement.text)) continue; |
||||
cmd.CommandText = statement.text; |
||||
try |
||||
{ |
||||
cmd.ExecuteNonQuery(); |
||||
count++; |
||||
OnQueryExecuted(statement); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
if (Error == null) |
||||
throw; |
||||
if (!OnScriptError(ex)) |
||||
break; |
||||
} |
||||
} |
||||
OnScriptCompleted(); |
||||
return count; |
||||
} |
||||
finally |
||||
{ |
||||
connection.Settings.AllowUserVariables = allowUserVars; |
||||
if (openedConnection) |
||||
{ |
||||
connection.Close(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
private void OnQueryExecuted(ScriptStatement statement) |
||||
{ |
||||
if (StatementExecuted != null) |
||||
{ |
||||
MySqlScriptEventArgs args = new MySqlScriptEventArgs(); |
||||
args.Statement = statement; |
||||
StatementExecuted(this, args); |
||||
} |
||||
} |
||||
|
||||
private void OnScriptCompleted() |
||||
{ |
||||
if (ScriptCompleted != null) |
||||
ScriptCompleted(this, EventArgs.Empty); |
||||
} |
||||
|
||||
private bool OnScriptError(Exception ex) |
||||
{ |
||||
if (Error != null) |
||||
{ |
||||
MySqlScriptErrorEventArgs args = new MySqlScriptErrorEventArgs(ex); |
||||
Error(this, args); |
||||
return args.Ignore; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private List<int> BreakScriptIntoLines() |
||||
{ |
||||
List<int> lineNumbers = new List<int>(); |
||||
|
||||
StringReader sr = new StringReader(query); |
||||
string line = sr.ReadLine(); |
||||
int pos = 0; |
||||
while (line != null) |
||||
{ |
||||
lineNumbers.Add(pos); |
||||
pos += line.Length; |
||||
line = sr.ReadLine(); |
||||
} |
||||
return lineNumbers; |
||||
} |
||||
|
||||
private static int FindLineNumber(int position, List<int> lineNumbers) |
||||
{ |
||||
int i = 0; |
||||
while (i < lineNumbers.Count && position < lineNumbers[i]) |
||||
i++; |
||||
return i; |
||||
} |
||||
|
||||
private List<ScriptStatement> BreakIntoStatements(bool ansiQuotes, bool noBackslashEscapes) |
||||
{ |
||||
string currentDelimiter = Delimiter; |
||||
int startPos = 0; |
||||
List<ScriptStatement> statements = new List<ScriptStatement>(); |
||||
List<int> lineNumbers = BreakScriptIntoLines(); |
||||
MySqlTokenizer tokenizer = new MySqlTokenizer(query); |
||||
|
||||
tokenizer.AnsiQuotes = ansiQuotes; |
||||
tokenizer.BackslashEscapes = !noBackslashEscapes; |
||||
|
||||
string token = tokenizer.NextToken(); |
||||
while (token != null) |
||||
{ |
||||
if (!tokenizer.Quoted) |
||||
{ |
||||
if (token.ToLower(CultureInfo.InvariantCulture) == "delimiter") |
||||
{ |
||||
tokenizer.NextToken(); |
||||
AdjustDelimiterEnd(tokenizer); |
||||
currentDelimiter = query.Substring(tokenizer.StartIndex, |
||||
tokenizer.StopIndex - tokenizer.StartIndex + 1).Trim(); |
||||
startPos = tokenizer.StopIndex; |
||||
} |
||||
else |
||||
{ |
||||
// this handles the case where our tokenizer reads part of the |
||||
// delimiter |
||||
if (currentDelimiter.StartsWith(token)) |
||||
{ |
||||
if ((tokenizer.StartIndex + currentDelimiter.Length) <= query.Length) |
||||
{ |
||||
if (query.Substring(tokenizer.StartIndex, currentDelimiter.Length) == currentDelimiter) |
||||
{ |
||||
token = currentDelimiter; |
||||
tokenizer.Position = tokenizer.StartIndex + currentDelimiter.Length; |
||||
tokenizer.StopIndex = tokenizer.Position; |
||||
} |
||||
} |
||||
} |
||||
|
||||
int delimiterPos = token.IndexOf(currentDelimiter, StringComparison.InvariantCultureIgnoreCase); |
||||
if (delimiterPos != -1) |
||||
{ |
||||
int endPos = tokenizer.StopIndex - token.Length + delimiterPos; |
||||
if (tokenizer.StopIndex == query.Length - 1) |
||||
endPos++; |
||||
string currentQuery = query.Substring(startPos, endPos - startPos); |
||||
ScriptStatement statement = new ScriptStatement(); |
||||
statement.text = currentQuery.Trim(); |
||||
statement.line = FindLineNumber(startPos, lineNumbers); |
||||
statement.position = startPos - lineNumbers[statement.line]; |
||||
statements.Add(statement); |
||||
startPos = endPos + currentDelimiter.Length; |
||||
} |
||||
} |
||||
} |
||||
token = tokenizer.NextToken(); |
||||
} |
||||
|
||||
// now clean up the last statement |
||||
if (startPos < query.Length-1) |
||||
{ |
||||
string sqlLeftOver = query.Substring(startPos).Trim(); |
||||
if (!String.IsNullOrEmpty(sqlLeftOver)) |
||||
{ |
||||
ScriptStatement statement = new ScriptStatement(); |
||||
statement.text = sqlLeftOver; |
||||
statement.line = FindLineNumber(startPos, lineNumbers); |
||||
statement.position = startPos - lineNumbers[statement.line]; |
||||
statements.Add(statement); |
||||
} |
||||
} |
||||
return statements; |
||||
} |
||||
|
||||
private void AdjustDelimiterEnd(MySqlTokenizer tokenizer) |
||||
{ |
||||
int pos = tokenizer.StopIndex; |
||||
char c = query[pos]; |
||||
|
||||
while (!Char.IsWhiteSpace(c) && pos < (query.Length-1)) |
||||
{ |
||||
c = query[++pos]; |
||||
} |
||||
tokenizer.StopIndex = pos; |
||||
tokenizer.Position = pos; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// |
||||
/// </summary> |
||||
public delegate void MySqlStatementExecutedEventHandler(object sender, MySqlScriptEventArgs args); |
||||
/// <summary> |
||||
/// |
||||
/// </summary> |
||||
public delegate void MySqlScriptErrorEventHandler(object sender, MySqlScriptErrorEventArgs args); |
||||
|
||||
/// <summary> |
||||
/// |
||||
/// </summary> |
||||
public class MySqlScriptEventArgs : EventArgs |
||||
{ |
||||
private ScriptStatement statement; |
||||
|
||||
internal ScriptStatement Statement |
||||
{ |
||||
set { this.statement = value; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the statement text. |
||||
/// </summary> |
||||
/// <value>The statement text.</value> |
||||
public string StatementText |
||||
{ |
||||
get { return statement.text; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the line. |
||||
/// </summary> |
||||
/// <value>The line.</value> |
||||
public int Line |
||||
{ |
||||
get { return statement.line; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the position. |
||||
/// </summary> |
||||
/// <value>The position.</value> |
||||
public int Position |
||||
{ |
||||
get { return statement.position; } |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// |
||||
/// </summary> |
||||
public class MySqlScriptErrorEventArgs : MySqlScriptEventArgs |
||||
{ |
||||
private Exception exception; |
||||
private bool ignore; |
||||
|
||||
/// <summary> |
||||
/// Initializes a new instance of the <see cref="MySqlScriptErrorEventArgs"/> class. |
||||
/// </summary> |
||||
/// <param name="exception">The exception.</param> |
||||
public MySqlScriptErrorEventArgs(Exception exception) : base() |
||||
{ |
||||
this.exception = exception; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the exception. |
||||
/// </summary> |
||||
/// <value>The exception.</value> |
||||
public Exception Exception |
||||
{ |
||||
get { return exception; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a value indicating whether this <see cref="MySqlScriptErrorEventArgs"/> is ignore. |
||||
/// </summary> |
||||
/// <value><c>true</c> if ignore; otherwise, <c>false</c>.</value> |
||||
public bool Ignore |
||||
{ |
||||
get { return ignore; } |
||||
set { ignore = value; } |
||||
} |
||||
} |
||||
|
||||
struct ScriptStatement |
||||
{ |
||||
public string text; |
||||
public int line; |
||||
public int position; |
||||
} |
||||
} |
@ -0,0 +1,241 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.IO; |
||||
using System.Diagnostics; |
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for MySqlStream. |
||||
/// </summary> |
||||
internal class MySqlStream |
||||
{ |
||||
private byte sequenceByte; |
||||
private MemoryStream bufferStream; |
||||
private int maxBlockSize; |
||||
private ulong maxPacketSize; |
||||
private byte[] packetHeader = new byte[4]; |
||||
MySqlPacket packet; |
||||
TimedStream timedStream; |
||||
Stream inStream; |
||||
Stream outStream; |
||||
|
||||
|
||||
public MySqlStream(Encoding encoding) |
||||
{ |
||||
// we have no idea what the real value is so we start off with the max value |
||||
// The real value will be set in NativeDriver.Configure() |
||||
maxPacketSize = ulong.MaxValue; |
||||
|
||||
// we default maxBlockSize to MaxValue since we will get the 'real' value in |
||||
// the authentication handshake and we know that value will not exceed |
||||
// true maxBlockSize prior to that. |
||||
maxBlockSize = Int32.MaxValue; |
||||
|
||||
packet = new MySqlPacket(encoding); |
||||
bufferStream = new MemoryStream(); |
||||
} |
||||
|
||||
public MySqlStream(Stream baseStream, Encoding encoding, bool compress) |
||||
: this(encoding) |
||||
{ |
||||
timedStream = new TimedStream(baseStream); |
||||
Stream stream; |
||||
if (compress) |
||||
stream = new CompressedStream(timedStream); |
||||
else |
||||
stream = timedStream; |
||||
|
||||
inStream = new BufferedStream(stream); |
||||
outStream = stream; |
||||
} |
||||
|
||||
public void Close() |
||||
{ |
||||
outStream.Close(); |
||||
inStream.Close(); |
||||
timedStream.Close(); |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public Encoding Encoding |
||||
{ |
||||
get { return packet.Encoding; } |
||||
set { packet.Encoding = value; } |
||||
} |
||||
|
||||
public void ResetTimeout(int timeout) |
||||
{ |
||||
timedStream.ResetTimeout(timeout); |
||||
} |
||||
|
||||
public byte SequenceByte |
||||
{ |
||||
get { return sequenceByte; } |
||||
set { sequenceByte = value; } |
||||
} |
||||
|
||||
public int MaxBlockSize |
||||
{ |
||||
get { return maxBlockSize; } |
||||
set { maxBlockSize = value; } |
||||
} |
||||
|
||||
public ulong MaxPacketSize |
||||
{ |
||||
get { return maxPacketSize; } |
||||
set { maxPacketSize = value; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Packet methods |
||||
|
||||
/// <summary> |
||||
/// ReadPacket is called by NativeDriver to start reading the next |
||||
/// packet on the stream. |
||||
/// </summary> |
||||
public MySqlPacket ReadPacket() |
||||
{ |
||||
//Debug.Assert(packet.Position == packet.Length); |
||||
|
||||
// make sure we have read all the data from the previous packet |
||||
//Debug.Assert(HasMoreData == false, "HasMoreData is true in OpenPacket"); |
||||
|
||||
LoadPacket(); |
||||
|
||||
// now we check if this packet is a server error |
||||
if (packet.Buffer[0] == 0xff) |
||||
{ |
||||
packet.ReadByte(); // read off the 0xff |
||||
|
||||
int code = packet.ReadInteger(2); |
||||
string msg = packet.ReadString(); |
||||
if (msg.StartsWith("#")) |
||||
{ |
||||
msg.Substring(1, 5); /* state code */ |
||||
msg = msg.Substring(6); |
||||
} |
||||
throw new MySqlException(msg, code); |
||||
} |
||||
return packet; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Reads the specified number of bytes from the stream and stores them at given |
||||
/// offset in the buffer. |
||||
/// Throws EndOfStreamException if not all bytes can be read. |
||||
/// </summary> |
||||
/// <param name="stream">Stream to read from</param> |
||||
/// <param name="buffer"> Array to store bytes read from the stream </param> |
||||
/// <param name="offset">The offset in buffer at which to begin storing the data read from the current stream. </param> |
||||
/// <param name="count">Number of bytes to read</param> |
||||
internal static void ReadFully(Stream stream, byte[] buffer, int offset, int count) |
||||
{ |
||||
int numRead = 0; |
||||
int numToRead = count; |
||||
while (numToRead > 0) |
||||
{ |
||||
int read = stream.Read(buffer, offset + numRead, numToRead); |
||||
if (read == 0) |
||||
{ |
||||
throw new EndOfStreamException(); |
||||
} |
||||
numRead += read; |
||||
numToRead -= read; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// LoadPacket loads up and decodes the header of the incoming packet. |
||||
/// </summary> |
||||
public void LoadPacket() |
||||
{ |
||||
try |
||||
{ |
||||
packet.Length = 0; |
||||
int offset = 0; |
||||
while (true) |
||||
{ |
||||
ReadFully(inStream, packetHeader, 0, 4); |
||||
sequenceByte = (byte)(packetHeader[3]+1); |
||||
int length = (int)(packetHeader[0] + (packetHeader[1] << 8) + |
||||
(packetHeader[2] << 16)); |
||||
|
||||
// make roo for the next block |
||||
packet.Length += length; |
||||
|
||||
ReadFully(inStream, packet.Buffer, offset, length); |
||||
offset += length; |
||||
|
||||
// if this block was < maxBlock then it's last one in a multipacket series |
||||
if (length < maxBlockSize) break; |
||||
} |
||||
packet.Position = 0; |
||||
} |
||||
catch (IOException ioex) |
||||
{ |
||||
throw new MySqlException(Resources.ReadFromStreamFailed, true, ioex); |
||||
} |
||||
} |
||||
|
||||
public void SendPacket(MySqlPacket packet) |
||||
{ |
||||
byte[] buffer = packet.Buffer; |
||||
int length = packet.Position-4; |
||||
|
||||
if ((ulong)length > maxPacketSize) |
||||
throw new MySqlException(Resources.QueryTooLarge, (int)MySqlErrorCode.PacketTooLarge); |
||||
|
||||
int offset = 0; |
||||
while (length > 0) |
||||
{ |
||||
int lenToSend = length > maxBlockSize ? maxBlockSize : length; |
||||
buffer[offset] = (byte)(lenToSend & 0xff); |
||||
buffer[offset+1] = (byte)((lenToSend >> 8) & 0xff); |
||||
buffer[offset+2] = (byte)((lenToSend >> 16) & 0xff); |
||||
buffer[offset+3] = sequenceByte++; |
||||
|
||||
outStream.Write(buffer, offset, lenToSend + 4); |
||||
outStream.Flush(); |
||||
length -= lenToSend; |
||||
offset += lenToSend; |
||||
} |
||||
} |
||||
|
||||
public void SendEntirePacketDirectly(byte[] buffer, int count) |
||||
{ |
||||
buffer[0] = (byte)(count & 0xff); |
||||
buffer[1] = (byte)((count >> 8) & 0xff); |
||||
buffer[2] = (byte)((count >> 16) & 0xff); |
||||
buffer[3] = sequenceByte++; |
||||
outStream.Write(buffer, 0, count + 4); |
||||
outStream.Flush(); |
||||
} |
||||
|
||||
#endregion |
||||
} |
||||
} |
@ -0,0 +1,410 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for ClientParam. |
||||
/// </summary> |
||||
[Flags] |
||||
internal enum ClientFlags : ulong |
||||
{ |
||||
LONG_PASSWORD = 1, // new more secure passwords |
||||
FOUND_ROWS = 2, // found instead of affected rows |
||||
LONG_FLAG = 4, // Get all column flags |
||||
CONNECT_WITH_DB = 8, // One can specify db on connect |
||||
NO_SCHEMA = 16, // Don't allow db.table.column |
||||
COMPRESS = 32, // Client can use compression protocol |
||||
ODBC = 64, // ODBC client |
||||
LOCAL_FILES = 128, // Can use LOAD DATA LOCAL |
||||
IGNORE_SPACE = 256, // Ignore spaces before '(' |
||||
PROTOCOL_41 = 512, // Support new 4.1 protocol |
||||
INTERACTIVE = 1024, // This is an interactive client |
||||
SSL = 2048, // Switch to SSL after handshake |
||||
IGNORE_SIGPIPE = 4096, // IGNORE sigpipes |
||||
TRANSACTIONS = 8192, // Client knows about transactions |
||||
RESERVED = 16384, // old 4.1 protocol flag |
||||
SECURE_CONNECTION = 32768, // new 4.1 authentication |
||||
MULTI_STATEMENTS = 65536, // Allow multi-stmt support |
||||
MULTI_RESULTS = 131072, // Allow multiple resultsets |
||||
PS_MULTI_RESULTS = 1UL << 18 // allow multi results using PS protocol |
||||
} |
||||
|
||||
[Flags] |
||||
internal enum ServerStatusFlags |
||||
{ |
||||
InTransaction = 1, // Transaction has started |
||||
AutoCommitMode = 2, // Server in auto_commit mode |
||||
MoreResults = 4, // More results on server |
||||
AnotherQuery = 8, // Multi query - next query exists |
||||
BadIndex = 16, |
||||
NoIndex = 32, |
||||
CursorExists = 64, |
||||
LastRowSent = 128, |
||||
OutputParameters = 4096 |
||||
} |
||||
|
||||
|
||||
/// <summary> |
||||
/// DB Operations Code |
||||
/// </summary> |
||||
internal enum DBCmd : byte |
||||
{ |
||||
SLEEP = 0, |
||||
QUIT = 1, |
||||
INIT_DB = 2, |
||||
QUERY = 3, |
||||
FIELD_LIST = 4, |
||||
CREATE_DB = 5, |
||||
DROP_DB = 6, |
||||
RELOAD = 7, |
||||
SHUTDOWN = 8, |
||||
STATISTICS = 9, |
||||
PROCESS_INFO = 10, |
||||
CONNECT = 11, |
||||
PROCESS_KILL = 12, |
||||
DEBUG = 13, |
||||
PING = 14, |
||||
TIME = 15, |
||||
DELAYED_INSERT = 16, |
||||
CHANGE_USER = 17, |
||||
BINLOG_DUMP = 18, |
||||
TABLE_DUMP = 19, |
||||
CONNECT_OUT = 20, |
||||
REGISTER_SLAVE = 21, |
||||
PREPARE = 22, |
||||
EXECUTE = 23, |
||||
LONG_DATA = 24, |
||||
CLOSE_STMT = 25, |
||||
RESET_STMT = 26, |
||||
SET_OPTION = 27, |
||||
FETCH = 28 |
||||
} |
||||
|
||||
|
||||
/// <summary> |
||||
/// Specifies MySQL specific data type of a field, property, for use in a <see cref="MySqlParameter"/>. |
||||
/// </summary> |
||||
public enum MySqlDbType |
||||
{ |
||||
/// <summary> |
||||
/// <see cref="Decimal"/> |
||||
/// <para>A fixed precision and scale numeric value between -1038 |
||||
/// -1 and 10 38 -1.</para> |
||||
/// </summary> |
||||
Decimal = 0, |
||||
/// <summary> |
||||
/// <see cref="Byte"/><para>The signed range is -128 to 127. The unsigned |
||||
/// range is 0 to 255.</para> |
||||
/// </summary> |
||||
Byte = 1, |
||||
/// <summary> |
||||
/// <see cref="Int16"/><para>A 16-bit signed integer. The signed range is |
||||
/// -32768 to 32767. The unsigned range is 0 to 65535</para> |
||||
/// </summary> |
||||
Int16 = 2, |
||||
/// <summary> |
||||
/// Specifies a 24 (3 byte) signed or unsigned value. |
||||
/// </summary> |
||||
Int24 = 9, |
||||
/// <summary> |
||||
/// <see cref="Int32"/><para>A 32-bit signed integer</para> |
||||
/// </summary> |
||||
Int32 = 3, |
||||
/// <summary> |
||||
/// <see cref="Int64"/><para>A 64-bit signed integer.</para> |
||||
/// </summary> |
||||
Int64 = 8, |
||||
/// <summary> |
||||
/// <see cref="Single"/><para>A small (single-precision) floating-point |
||||
/// number. Allowable values are -3.402823466E+38 to -1.175494351E-38, |
||||
/// 0, and 1.175494351E-38 to 3.402823466E+38.</para> |
||||
/// </summary> |
||||
Float = 4, |
||||
/// <summary> |
||||
/// <see cref="Double"/><para>A normal-size (double-precision) |
||||
/// floating-point number. Allowable values are -1.7976931348623157E+308 |
||||
/// to -2.2250738585072014E-308, 0, and 2.2250738585072014E-308 to |
||||
/// 1.7976931348623157E+308.</para> |
||||
/// </summary> |
||||
Double = 5, |
||||
/// <summary> |
||||
/// A timestamp. The range is '1970-01-01 00:00:00' to sometime in the |
||||
/// year 2037 |
||||
/// </summary> |
||||
Timestamp = 7, |
||||
///<summary> |
||||
///Date The supported range is '1000-01-01' to '9999-12-31'. |
||||
///</summary> |
||||
Date = 10, |
||||
/// <summary> |
||||
/// Time <para>The range is '-838:59:59' to '838:59:59'.</para> |
||||
/// </summary> |
||||
Time = 11, |
||||
///<summary> |
||||
///DateTime The supported range is '1000-01-01 00:00:00' to |
||||
///'9999-12-31 23:59:59'. |
||||
///</summary> |
||||
DateTime = 12, |
||||
///<summary> |
||||
///Datetime The supported range is '1000-01-01 00:00:00' to |
||||
///'9999-12-31 23:59:59'. |
||||
///</summary> |
||||
[Obsolete("The Datetime enum value is obsolete. Please use DateTime.")] |
||||
Datetime = 12, |
||||
/// <summary> |
||||
/// A year in 2- or 4-digit format (default is 4-digit). The |
||||
/// allowable values are 1901 to 2155, 0000 in the 4-digit year |
||||
/// format, and 1970-2069 if you use the 2-digit format (70-69). |
||||
/// </summary> |
||||
Year = 13, |
||||
/// <summary> |
||||
/// <b>Obsolete</b> Use Datetime or Date type |
||||
/// </summary> |
||||
Newdate = 14, |
||||
/// <summary> |
||||
/// A variable-length string containing 0 to 65535 characters |
||||
/// </summary> |
||||
VarString = 15, |
||||
/// <summary> |
||||
/// Bit-field data type |
||||
/// </summary> |
||||
Bit = 16, |
||||
/// <summary> |
||||
/// New Decimal |
||||
/// </summary> |
||||
NewDecimal = 246, |
||||
/// <summary> |
||||
/// An enumeration. A string object that can have only one value, |
||||
/// chosen from the list of values 'value1', 'value2', ..., NULL |
||||
/// or the special "" error value. An ENUM can have a maximum of |
||||
/// 65535 distinct values |
||||
/// </summary> |
||||
Enum = 247, |
||||
/// <summary> |
||||
/// A set. A string object that can have zero or more values, each |
||||
/// of which must be chosen from the list of values 'value1', 'value2', |
||||
/// ... A SET can have a maximum of 64 members. |
||||
/// </summary> |
||||
Set = 248, |
||||
/// <summary> |
||||
/// A binary column with a maximum length of 255 (2^8 - 1) |
||||
/// characters |
||||
/// </summary> |
||||
TinyBlob = 249, |
||||
/// <summary> |
||||
/// A binary column with a maximum length of 16777215 (2^24 - 1) bytes. |
||||
/// </summary> |
||||
MediumBlob = 250, |
||||
/// <summary> |
||||
/// A binary column with a maximum length of 4294967295 or |
||||
/// 4G (2^32 - 1) bytes. |
||||
/// </summary> |
||||
LongBlob = 251, |
||||
/// <summary> |
||||
/// A binary column with a maximum length of 65535 (2^16 - 1) bytes. |
||||
/// </summary> |
||||
Blob = 252, |
||||
/// <summary> |
||||
/// A variable-length string containing 0 to 255 bytes. |
||||
/// </summary> |
||||
VarChar = 253, |
||||
/// <summary> |
||||
/// A fixed-length string. |
||||
/// </summary> |
||||
String = 254, |
||||
/// <summary> |
||||
/// Geometric (GIS) data type. |
||||
/// </summary> |
||||
Geometry = 255, |
||||
/// <summary> |
||||
/// Unsigned 8-bit value. |
||||
/// </summary> |
||||
UByte = 501, |
||||
/// <summary> |
||||
/// Unsigned 16-bit value. |
||||
/// </summary> |
||||
UInt16 = 502, |
||||
/// <summary> |
||||
/// Unsigned 24-bit value. |
||||
/// </summary> |
||||
UInt24 = 509, |
||||
/// <summary> |
||||
/// Unsigned 32-bit value. |
||||
/// </summary> |
||||
UInt32 = 503, |
||||
/// <summary> |
||||
/// Unsigned 64-bit value. |
||||
/// </summary> |
||||
UInt64 = 508, |
||||
/// <summary> |
||||
/// Fixed length binary string. |
||||
/// </summary> |
||||
Binary = 600, |
||||
/// <summary> |
||||
/// Variable length binary string. |
||||
/// </summary> |
||||
VarBinary = 601, |
||||
/// <summary> |
||||
/// A text column with a maximum length of 255 (2^8 - 1) characters. |
||||
/// </summary> |
||||
TinyText = 749, |
||||
/// <summary> |
||||
/// A text column with a maximum length of 16777215 (2^24 - 1) characters. |
||||
/// </summary> |
||||
MediumText = 750, |
||||
/// <summary> |
||||
/// A text column with a maximum length of 4294967295 or |
||||
/// 4G (2^32 - 1) characters. |
||||
/// </summary> |
||||
LongText = 751, |
||||
/// <summary> |
||||
/// A text column with a maximum length of 65535 (2^16 - 1) characters. |
||||
/// </summary> |
||||
Text = 752, |
||||
/// <summary> |
||||
/// A guid column |
||||
/// </summary> |
||||
Guid = 800 |
||||
} ; |
||||
|
||||
|
||||
internal enum Field_Type : byte |
||||
{ |
||||
DECIMAL = 0, |
||||
BYTE = 1, |
||||
SHORT = 2, |
||||
LONG = 3, |
||||
FLOAT = 4, |
||||
DOUBLE = 5, |
||||
NULL = 6, |
||||
TIMESTAMP = 7, |
||||
LONGLONG = 8, |
||||
INT24 = 9, |
||||
DATE = 10, |
||||
TIME = 11, |
||||
DATETIME = 12, |
||||
YEAR = 13, |
||||
NEWDATE = 14, |
||||
ENUM = 247, |
||||
SET = 248, |
||||
TINY_BLOB = 249, |
||||
MEDIUM_BLOB = 250, |
||||
LONG_BLOB = 251, |
||||
BLOB = 252, |
||||
VAR_STRING = 253, |
||||
STRING = 254, |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Allows the user to specify the type of connection that should |
||||
/// be used. |
||||
/// </summary> |
||||
public enum MySqlConnectionProtocol |
||||
{ |
||||
/// <summary> |
||||
/// TCP/IP style connection. Works everywhere. |
||||
/// </summary> |
||||
Sockets = 1, |
||||
Socket = 1, |
||||
Tcp = 1, |
||||
/// <summary> |
||||
/// Named pipe connection. Works only on Windows systems. |
||||
/// </summary> |
||||
Pipe = 2, |
||||
NamedPipe = 2, |
||||
/// <summary> |
||||
/// Unix domain socket connection. Works only with Unix systems. |
||||
/// </summary> |
||||
UnixSocket = 3, |
||||
Unix = 3, |
||||
/// <summary> |
||||
/// Shared memory connection. Currently works only with Windows systems. |
||||
/// </summary> |
||||
SharedMemory = 4, |
||||
Memory = 4 |
||||
} |
||||
|
||||
/// <summary> |
||||
/// SSL options for connection. |
||||
/// </summary> |
||||
public enum MySqlSslMode |
||||
{ |
||||
/// <summary> |
||||
/// Do not use SSL. |
||||
/// </summary> |
||||
None, |
||||
/// <summary> |
||||
/// Use SSL, if server supports it. |
||||
/// </summary> |
||||
Preferred, |
||||
Prefered = Preferred, |
||||
/// <summary> |
||||
/// Always use SSL. Deny connection if server does not support SSL. |
||||
/// Do not perform server certificate validation. |
||||
/// </summary> |
||||
Required, |
||||
/// <summary> |
||||
/// Always use SSL. Validate server SSL certificate, but different host name mismatch. |
||||
/// </summary> |
||||
VerifyCA, |
||||
/// <summary> |
||||
/// Always use SSL and perform full certificate validation. |
||||
/// </summary> |
||||
VerifyFull |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Specifies the connection types supported |
||||
/// </summary> |
||||
public enum MySqlDriverType |
||||
{ |
||||
/// <summary> |
||||
/// Use TCP/IP sockets. |
||||
/// </summary> |
||||
Native, |
||||
/// <summary> |
||||
/// Use client library. |
||||
/// </summary> |
||||
Client, |
||||
/// <summary> |
||||
/// Use MySQL embedded server. |
||||
/// </summary> |
||||
Embedded |
||||
} |
||||
|
||||
public enum MySqlCertificateStoreLocation |
||||
{ |
||||
/// <summary> |
||||
/// Do not use certificate store |
||||
/// </summary> |
||||
None, |
||||
/// <summary> |
||||
/// Use certificate store for the current user |
||||
/// </summary> |
||||
CurrentUser, |
||||
/// <summary> |
||||
/// User certificate store for the machine |
||||
/// </summary> |
||||
LocalMachine |
||||
} |
||||
} |
@ -0,0 +1,880 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Diagnostics; |
||||
using System.IO; |
||||
using MySql.Data.Common; |
||||
using MySql.Data.Types; |
||||
using System.Security.Cryptography.X509Certificates; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using System.Text; |
||||
#if !CF |
||||
using System.Net.Security; |
||||
using System.Security.Authentication; |
||||
using System.Globalization; |
||||
using System.Text; |
||||
#endif |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for Driver. |
||||
/// </summary> |
||||
internal class NativeDriver : IDriver |
||||
{ |
||||
private DBVersion version; |
||||
private int threadId; |
||||
protected String encryptionSeed; |
||||
protected ServerStatusFlags serverStatus; |
||||
protected MySqlStream stream; |
||||
protected Stream baseStream; |
||||
private BitArray nullMap; |
||||
private MySqlPacket packet; |
||||
private ClientFlags connectionFlags; |
||||
private Driver owner; |
||||
private int warnings; |
||||
|
||||
public NativeDriver(Driver owner) |
||||
{ |
||||
this.owner = owner; |
||||
threadId = -1; |
||||
} |
||||
|
||||
public ClientFlags Flags |
||||
{ |
||||
get { return connectionFlags; } |
||||
} |
||||
|
||||
public int ThreadId |
||||
{ |
||||
get { return threadId; } |
||||
} |
||||
|
||||
public DBVersion Version |
||||
{ |
||||
get { return version; } |
||||
} |
||||
|
||||
public ServerStatusFlags ServerStatus |
||||
{ |
||||
get { return serverStatus; } |
||||
} |
||||
|
||||
public int WarningCount |
||||
{ |
||||
get { return warnings; } |
||||
} |
||||
|
||||
public MySqlPacket Packet |
||||
{ |
||||
get { return packet; } |
||||
} |
||||
|
||||
private MySqlConnectionStringBuilder Settings |
||||
{ |
||||
get { return owner.Settings; } |
||||
} |
||||
|
||||
private Encoding Encoding |
||||
{ |
||||
get { return owner.Encoding; } |
||||
} |
||||
|
||||
private void HandleException(MySqlException ex) |
||||
{ |
||||
if (ex.IsFatal) |
||||
owner.Close(); |
||||
} |
||||
|
||||
private void ReadOk(bool read) |
||||
{ |
||||
try |
||||
{ |
||||
if (read) |
||||
packet = stream.ReadPacket(); |
||||
byte marker = (byte) packet.ReadByte(); |
||||
if (marker != 0) |
||||
throw new MySqlException("Out of sync with server", true, null); |
||||
|
||||
packet.ReadFieldLength(); /* affected rows */ |
||||
packet.ReadFieldLength(); /* last insert id */ |
||||
if (packet.HasMoreData) |
||||
{ |
||||
serverStatus = (ServerStatusFlags) packet.ReadInteger(2); |
||||
packet.ReadInteger(2); /* warning count */ |
||||
if (packet.HasMoreData) |
||||
{ |
||||
packet.ReadLenString(); /* message */ |
||||
} |
||||
} |
||||
} |
||||
catch (MySqlException ex) |
||||
{ |
||||
HandleException(ex); |
||||
throw; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Sets the current database for the this connection |
||||
/// </summary> |
||||
/// <param name="dbName"></param> |
||||
public void SetDatabase(string dbName) |
||||
{ |
||||
byte[] dbNameBytes = Encoding.GetBytes(dbName); |
||||
|
||||
packet.Clear(); |
||||
packet.WriteByte((byte)DBCmd.INIT_DB); |
||||
packet.Write(dbNameBytes); |
||||
ExecutePacket(packet); |
||||
|
||||
ReadOk(true); |
||||
} |
||||
|
||||
public void Configure() |
||||
{ |
||||
stream.MaxPacketSize = (ulong)owner.MaxPacketSize; |
||||
stream.Encoding = Encoding; |
||||
} |
||||
|
||||
public void Open() |
||||
{ |
||||
// connect to one of our specified hosts |
||||
try |
||||
{ |
||||
#if !CF |
||||
if (Settings.ConnectionProtocol == MySqlConnectionProtocol.SharedMemory) |
||||
{ |
||||
SharedMemoryStream str = new SharedMemoryStream(Settings.SharedMemoryName); |
||||
str.Open(Settings.ConnectionTimeout); |
||||
baseStream = str; |
||||
} |
||||
else |
||||
{ |
||||
#endif |
||||
string pipeName = Settings.PipeName; |
||||
if (Settings.ConnectionProtocol != MySqlConnectionProtocol.NamedPipe) |
||||
pipeName = null; |
||||
StreamCreator sc = new StreamCreator(Settings.Server, Settings.Port, pipeName, |
||||
Settings.Keepalive); |
||||
baseStream = sc.GetStream(Settings.ConnectionTimeout); |
||||
#if !CF |
||||
} |
||||
#endif |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
throw new MySqlException(Resources.UnableToConnectToHost, |
||||
(int) MySqlErrorCode.UnableToConnectToHost, ex); |
||||
} |
||||
|
||||
if (baseStream == null) |
||||
throw new MySqlException(Resources.UnableToConnectToHost, |
||||
(int)MySqlErrorCode.UnableToConnectToHost); |
||||
|
||||
int maxSinglePacket = 255*255*255; |
||||
stream = new MySqlStream(baseStream, Encoding, false); |
||||
|
||||
stream.ResetTimeout((int)Settings.ConnectionTimeout*1000); |
||||
|
||||
// read off the welcome packet and parse out it's values |
||||
packet = stream.ReadPacket(); |
||||
int protocol = packet.ReadByte(); |
||||
string versionString = packet.ReadString(); |
||||
version = DBVersion.Parse(versionString); |
||||
if (!version.isAtLeast(4, 1, 1)) |
||||
throw new NotSupportedException(Resources.ServerTooOld); |
||||
threadId = packet.ReadInteger(4); |
||||
encryptionSeed = packet.ReadString(); |
||||
|
||||
maxSinglePacket = (256*256*256) - 1; |
||||
|
||||
// read in Server capabilities if they are provided |
||||
ClientFlags serverCaps = 0; |
||||
if (packet.HasMoreData) |
||||
serverCaps = (ClientFlags) packet.ReadInteger(2); |
||||
|
||||
/* New protocol with 16 bytes to describe server characteristics */ |
||||
owner.ConnectionCharSetIndex = (int)packet.ReadByte(); |
||||
|
||||
serverStatus = (ServerStatusFlags) packet.ReadInteger(2); |
||||
packet.Position += 13; |
||||
string seedPart2 = packet.ReadString(); |
||||
encryptionSeed += seedPart2; |
||||
|
||||
// based on our settings, set our connection flags |
||||
SetConnectionFlags(serverCaps); |
||||
|
||||
packet.Clear(); |
||||
packet.WriteInteger((int) connectionFlags, 4); |
||||
|
||||
#if !CF |
||||
if ((serverCaps & ClientFlags.SSL) ==0) |
||||
{ |
||||
if ((Settings.SslMode != MySqlSslMode.None) |
||||
&& (Settings.SslMode != MySqlSslMode.Preferred)) |
||||
{ |
||||
// Client requires SSL connections. |
||||
string message = String.Format(Resources.NoServerSSLSupport, |
||||
Settings.Server); |
||||
throw new MySqlException(message); |
||||
} |
||||
} |
||||
else if (Settings.SslMode != MySqlSslMode.None) |
||||
{ |
||||
stream.SendPacket(packet); |
||||
StartSSL(); |
||||
packet.Clear(); |
||||
packet.WriteInteger((int) connectionFlags, 4); |
||||
} |
||||
#endif |
||||
|
||||
packet.WriteInteger(maxSinglePacket, 4); |
||||
packet.WriteByte(8); |
||||
packet.Write(new byte[23]); |
||||
|
||||
Authenticate(); |
||||
|
||||
// if we are using compression, then we use our CompressedStream class |
||||
// to hide the ugliness of managing the compression |
||||
if ((connectionFlags & ClientFlags.COMPRESS) != 0) |
||||
stream = new MySqlStream(baseStream, Encoding, true); |
||||
|
||||
// give our stream the server version we are connected to. |
||||
// We may have some fields that are read differently based |
||||
// on the version of the server we are connected to. |
||||
packet.Version = version; |
||||
stream.MaxBlockSize = maxSinglePacket; |
||||
} |
||||
|
||||
#if !CF |
||||
|
||||
#region SSL |
||||
|
||||
/// <summary> |
||||
/// Retrieve client SSL certificates. Dependent on connection string |
||||
/// settings we use either file or store based certificates. |
||||
/// </summary> |
||||
private X509CertificateCollection GetClientCertificates() |
||||
{ |
||||
X509CertificateCollection certs = new X509CertificateCollection(); |
||||
|
||||
// Check for file-based certificate |
||||
if (Settings.CertificateFile != null) |
||||
{ |
||||
X509Certificate2 clientCert = new X509Certificate2(Settings.CertificateFile, |
||||
Settings.CertificatePassword); |
||||
certs.Add(clientCert); |
||||
return certs; |
||||
} |
||||
|
||||
if (Settings.CertificateStoreLocation == MySqlCertificateStoreLocation.None) |
||||
return certs; |
||||
|
||||
StoreLocation location = |
||||
(Settings.CertificateStoreLocation == MySqlCertificateStoreLocation.CurrentUser) ? |
||||
StoreLocation.CurrentUser : StoreLocation.LocalMachine; |
||||
|
||||
// Check for store-based certificate |
||||
X509Store store = new X509Store(StoreName.My, location); |
||||
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); |
||||
|
||||
|
||||
if (Settings.CertificateThumbprint == null) |
||||
{ |
||||
// Return all certificates from the store. |
||||
certs.AddRange(store.Certificates); |
||||
return certs; |
||||
} |
||||
|
||||
// Find certificate with given thumbprint |
||||
certs.AddRange(store.Certificates.Find(X509FindType.FindByThumbprint, |
||||
Settings.CertificateThumbprint, true)); |
||||
|
||||
if (certs.Count == 0) |
||||
{ |
||||
throw new MySqlException("Certificate with Thumbprint " + |
||||
Settings.CertificateThumbprint + " not found"); |
||||
} |
||||
return certs; |
||||
} |
||||
|
||||
|
||||
private void StartSSL() |
||||
{ |
||||
RemoteCertificateValidationCallback sslValidateCallback = |
||||
new RemoteCertificateValidationCallback(ServerCheckValidation); |
||||
SslStream ss = new SslStream(baseStream, true, sslValidateCallback, null); |
||||
X509CertificateCollection certs = GetClientCertificates(); |
||||
ss.AuthenticateAsClient(Settings.Server, certs, SslProtocols.Default, false); |
||||
baseStream = ss; |
||||
stream = new MySqlStream(ss, Encoding, false); |
||||
stream.SequenceByte = 2; |
||||
|
||||
} |
||||
|
||||
private bool ServerCheckValidation(object sender, X509Certificate certificate, |
||||
X509Chain chain, SslPolicyErrors sslPolicyErrors) |
||||
{ |
||||
if (sslPolicyErrors == SslPolicyErrors.None) |
||||
return true; |
||||
|
||||
if (Settings.SslMode == MySqlSslMode.Preferred || |
||||
Settings.SslMode == MySqlSslMode.Required) |
||||
{ |
||||
//Tolerate all certificate errors. |
||||
return true; |
||||
} |
||||
|
||||
if (Settings.SslMode == MySqlSslMode.VerifyCA && |
||||
sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch) |
||||
{ |
||||
// Tolerate name mismatch in certificate, if full validation is not requested. |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
|
||||
#endregion |
||||
|
||||
#endif |
||||
|
||||
#region Authentication |
||||
|
||||
/// <summary> |
||||
/// Return the appropriate set of connection flags for our |
||||
/// server capabilities and our user requested options. |
||||
/// </summary> |
||||
private void SetConnectionFlags(ClientFlags serverCaps) |
||||
{ |
||||
// allow load data local infile |
||||
ClientFlags flags = ClientFlags.LOCAL_FILES; |
||||
|
||||
if (!Settings.UseAffectedRows) |
||||
flags |= ClientFlags.FOUND_ROWS; |
||||
|
||||
flags |= ClientFlags.PROTOCOL_41; |
||||
// Need this to get server status values |
||||
flags |= ClientFlags.TRANSACTIONS; |
||||
|
||||
// user allows/disallows batch statements |
||||
if (Settings.AllowBatch) |
||||
flags |= ClientFlags.MULTI_STATEMENTS; |
||||
|
||||
// We always allow multiple result sets |
||||
flags |= ClientFlags.MULTI_RESULTS; |
||||
|
||||
// if the server allows it, tell it that we want long column info |
||||
if ((serverCaps & ClientFlags.LONG_FLAG) != 0) |
||||
flags |= ClientFlags.LONG_FLAG; |
||||
|
||||
// if the server supports it and it was requested, then turn on compression |
||||
if ((serverCaps & ClientFlags.COMPRESS) != 0 && Settings.UseCompression) |
||||
flags |= ClientFlags.COMPRESS; |
||||
|
||||
flags |= ClientFlags.LONG_PASSWORD; // for long passwords |
||||
|
||||
// did the user request an interactive session? |
||||
if (Settings.InteractiveSession) |
||||
flags |= ClientFlags.INTERACTIVE; |
||||
|
||||
// if the server allows it and a database was specified, then indicate |
||||
// that we will connect with a database name |
||||
if ((serverCaps & ClientFlags.CONNECT_WITH_DB) != 0 && |
||||
Settings.Database != null && Settings.Database.Length > 0) |
||||
flags |= ClientFlags.CONNECT_WITH_DB; |
||||
|
||||
// if the server is requesting a secure connection, then we oblige |
||||
if ((serverCaps & ClientFlags.SECURE_CONNECTION) != 0) |
||||
flags |= ClientFlags.SECURE_CONNECTION; |
||||
|
||||
// if the server is capable of SSL and the user is requesting SSL |
||||
if ((serverCaps & ClientFlags.SSL) != 0 && Settings.SslMode != MySqlSslMode.None) |
||||
flags |= ClientFlags.SSL; |
||||
|
||||
// if the server supports output parameters, then we do too |
||||
//if ((serverCaps & ClientFlags.PS_MULTI_RESULTS) != 0) |
||||
flags |= ClientFlags.PS_MULTI_RESULTS; |
||||
|
||||
connectionFlags = flags; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Perform an authentication against a 4.1.1 server |
||||
/// </summary> |
||||
private void AuthenticateNew() |
||||
{ |
||||
if ((connectionFlags & ClientFlags.SECURE_CONNECTION) == 0) |
||||
AuthenticateOld(); |
||||
|
||||
packet.Write(Crypt.Get411Password(Settings.Password, encryptionSeed)); |
||||
if ((connectionFlags & ClientFlags.CONNECT_WITH_DB) != 0 && Settings.Database != null) |
||||
packet.WriteString(Settings.Database); |
||||
|
||||
stream.SendPacket(packet); |
||||
|
||||
// this result means the server wants us to send the password using |
||||
// old encryption |
||||
packet = stream.ReadPacket(); |
||||
if (packet.IsLastPacket) |
||||
{ |
||||
packet.Clear(); |
||||
packet.WriteString(Crypt.EncryptPassword( |
||||
Settings.Password, encryptionSeed.Substring(0, 8), true)); |
||||
stream.SendPacket(packet); |
||||
ReadOk(true); |
||||
} |
||||
else |
||||
ReadOk(false); |
||||
} |
||||
|
||||
private void AuthenticateOld() |
||||
{ |
||||
packet.WriteString(Crypt.EncryptPassword( |
||||
Settings.Password, encryptionSeed, true)); |
||||
if ((connectionFlags & ClientFlags.CONNECT_WITH_DB) != 0 && Settings.Database != null) |
||||
packet.WriteString(Settings.Database); |
||||
|
||||
stream.SendPacket(packet); |
||||
ReadOk(true); |
||||
} |
||||
|
||||
public void Authenticate() |
||||
{ |
||||
// write the user id to the auth packet |
||||
packet.WriteString(Settings.UserID); |
||||
AuthenticateNew(); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public void Reset() |
||||
{ |
||||
warnings = 0; |
||||
stream.SequenceByte = 0; |
||||
packet.Clear(); |
||||
packet.WriteByte((byte)DBCmd.CHANGE_USER); |
||||
Authenticate(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Query is the method that is called to send all queries to the server |
||||
/// </summary> |
||||
public void SendQuery(MySqlPacket queryPacket) |
||||
{ |
||||
warnings = 0; |
||||
queryPacket.Buffer[4] = (byte)DBCmd.QUERY; |
||||
ExecutePacket(queryPacket); |
||||
// the server will respond in one of several ways with the first byte indicating |
||||
// the type of response. |
||||
// 0 == ok packet. This indicates non-select queries |
||||
// 0xff == error packet. This is handled in stream.OpenPacket |
||||
// > 0 = number of columns in select query |
||||
// We don't actually read the result here since a single query can generate |
||||
// multiple resultsets and we don't want to duplicate code. See ReadResult |
||||
// Instead we set our internal server status flag to indicate that we have a query waiting. |
||||
// This flag will be maintained by ReadResult |
||||
serverStatus |= ServerStatusFlags.AnotherQuery; |
||||
} |
||||
|
||||
public void Close(bool isOpen) |
||||
{ |
||||
try |
||||
{ |
||||
if (isOpen) |
||||
{ |
||||
try |
||||
{ |
||||
packet.Clear(); |
||||
packet.WriteByte((byte)DBCmd.QUIT); |
||||
ExecutePacket(packet); |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
// Eat exception here. We should try to closing |
||||
// the stream anyway. |
||||
} |
||||
} |
||||
|
||||
if (stream != null) |
||||
stream.Close(); |
||||
stream = null; |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
// we are just going to eat any exceptions |
||||
// generated here |
||||
} |
||||
} |
||||
|
||||
public bool Ping() |
||||
{ |
||||
try |
||||
{ |
||||
packet.Clear(); |
||||
packet.WriteByte((byte)DBCmd.PING); |
||||
ExecutePacket(packet); |
||||
ReadOk(true); |
||||
return true; |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public int GetResult(ref int affectedRow, ref int insertedId) |
||||
{ |
||||
try |
||||
{ |
||||
packet = stream.ReadPacket(); |
||||
} |
||||
catch (TimeoutException) |
||||
{ |
||||
// Do not reset serverStatus, allow to reenter, e.g when |
||||
// ResultSet is closed. |
||||
throw; |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
serverStatus = 0; |
||||
throw; |
||||
} |
||||
|
||||
int fieldCount = (int)packet.ReadFieldLength(); |
||||
if (-1 == fieldCount) |
||||
{ |
||||
string filename = packet.ReadString(); |
||||
SendFileToServer(filename); |
||||
|
||||
return GetResult(ref affectedRow, ref insertedId); |
||||
} |
||||
else if (fieldCount == 0) |
||||
{ |
||||
// the code to read last packet will set these server status vars |
||||
// again if necessary. |
||||
serverStatus &= ~(ServerStatusFlags.AnotherQuery | |
||||
ServerStatusFlags.MoreResults); |
||||
affectedRow = (int)packet.ReadFieldLength(); |
||||
insertedId = (int)packet.ReadFieldLength(); |
||||
|
||||
serverStatus = (ServerStatusFlags)packet.ReadInteger(2); |
||||
warnings += packet.ReadInteger(2); |
||||
if (packet.HasMoreData) |
||||
{ |
||||
packet.ReadLenString(); //TODO: server message |
||||
} |
||||
} |
||||
return fieldCount; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Sends the specified file to the server. |
||||
/// This supports the LOAD DATA LOCAL INFILE |
||||
/// </summary> |
||||
/// <param name="filename"></param> |
||||
private void SendFileToServer(string filename) |
||||
{ |
||||
byte[] buffer = new byte[8196]; |
||||
|
||||
long len = 0; |
||||
try |
||||
{ |
||||
using (FileStream fs = new FileStream(filename, FileMode.Open, |
||||
FileAccess.Read)) |
||||
{ |
||||
len = fs.Length; |
||||
while (len > 0) |
||||
{ |
||||
int count = fs.Read(buffer, 4, (int)(len > 8192 ? 8192 : len)); |
||||
stream.SendEntirePacketDirectly(buffer, count); |
||||
len -= count; |
||||
} |
||||
stream.SendEntirePacketDirectly(buffer, 0); |
||||
} |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
throw new MySqlException("Error during LOAD DATA LOCAL INFILE", ex); |
||||
} |
||||
} |
||||
|
||||
private void ReadNullMap(int fieldCount) |
||||
{ |
||||
// if we are binary, then we need to load in our null bitmap |
||||
nullMap = null; |
||||
byte[] nullMapBytes = new byte[(fieldCount + 9)/8]; |
||||
packet.ReadByte(); |
||||
packet.Read(nullMapBytes, 0, nullMapBytes.Length); |
||||
nullMap = new BitArray(nullMapBytes); |
||||
} |
||||
|
||||
public IMySqlValue ReadColumnValue(int index, MySqlField field, IMySqlValue valObject) |
||||
{ |
||||
long length = -1; |
||||
bool isNull; |
||||
|
||||
if (nullMap != null) |
||||
isNull = nullMap[index + 2]; |
||||
else |
||||
{ |
||||
length = packet.ReadFieldLength(); |
||||
isNull = length == -1; |
||||
} |
||||
|
||||
packet.Encoding = field.Encoding; |
||||
packet.Version = version; |
||||
return valObject.ReadValue(packet, length, isNull); |
||||
} |
||||
|
||||
public void SkipColumnValue(IMySqlValue valObject) |
||||
{ |
||||
int length = -1; |
||||
if (nullMap == null) |
||||
{ |
||||
length = packet.ReadFieldLength(); |
||||
if (length == -1) return; |
||||
} |
||||
if (length > -1) |
||||
packet.Position += length; |
||||
else |
||||
valObject.SkipValue(packet); |
||||
} |
||||
|
||||
public void GetColumnsData(MySqlField[] columns) |
||||
{ |
||||
for (int i = 0; i < columns.Length; i++) |
||||
GetColumnData(columns[i]); |
||||
ReadEOF(); |
||||
} |
||||
|
||||
private void GetColumnData(MySqlField field) |
||||
{ |
||||
stream.Encoding = Encoding; |
||||
packet = stream.ReadPacket(); |
||||
field.Encoding = Encoding; |
||||
field.CatalogName = packet.ReadLenString(); |
||||
field.DatabaseName = packet.ReadLenString(); |
||||
field.TableName = packet.ReadLenString(); |
||||
field.RealTableName = packet.ReadLenString(); |
||||
field.ColumnName = packet.ReadLenString(); |
||||
field.OriginalColumnName = packet.ReadLenString(); |
||||
packet.ReadByte(); |
||||
field.CharacterSetIndex = packet.ReadInteger(2); |
||||
field.ColumnLength = packet.ReadInteger(4); |
||||
MySqlDbType type = (MySqlDbType)packet.ReadByte(); |
||||
ColumnFlags colFlags; |
||||
if ((connectionFlags & ClientFlags.LONG_FLAG) != 0) |
||||
colFlags = (ColumnFlags)packet.ReadInteger(2); |
||||
else |
||||
colFlags = (ColumnFlags)packet.ReadByte(); |
||||
field.Scale = (byte)packet.ReadByte(); |
||||
|
||||
if (packet.HasMoreData) |
||||
{ |
||||
packet.ReadInteger(2); // reserved |
||||
} |
||||
|
||||
if (type == MySqlDbType.Decimal || type == MySqlDbType.NewDecimal) |
||||
{ |
||||
field.Precision = (byte)(field.ColumnLength - (int)field.Scale); |
||||
if ((colFlags & ColumnFlags.UNSIGNED) != 0) |
||||
field.Precision++; |
||||
} |
||||
|
||||
field.SetTypeAndFlags(type, colFlags); |
||||
} |
||||
|
||||
private void ExecutePacket(MySqlPacket packetToExecute) |
||||
{ |
||||
try |
||||
{ |
||||
warnings = 0; |
||||
stream.SequenceByte = 0; |
||||
stream.SendPacket(packetToExecute); |
||||
} |
||||
catch (MySqlException ex) |
||||
{ |
||||
HandleException(ex); |
||||
throw; |
||||
} |
||||
} |
||||
|
||||
public void ExecuteStatement(MySqlPacket packetToExecute) |
||||
{ |
||||
warnings = 0; |
||||
packetToExecute.Buffer[4] = (byte)DBCmd.EXECUTE; |
||||
ExecutePacket(packetToExecute); |
||||
serverStatus |= ServerStatusFlags.AnotherQuery; |
||||
} |
||||
|
||||
private void CheckEOF() |
||||
{ |
||||
if (!packet.IsLastPacket) |
||||
throw new MySqlException("Expected end of data packet"); |
||||
|
||||
packet.ReadByte(); // read off the 254 |
||||
|
||||
if (packet.HasMoreData) |
||||
{ |
||||
warnings += packet.ReadInteger(2); |
||||
serverStatus = (ServerStatusFlags)packet.ReadInteger(2); |
||||
|
||||
// if we are at the end of this cursor based resultset, then we remove |
||||
// the last row sent status flag so our next fetch doesn't abort early |
||||
// and we remove this command result from our list of active CommandResult objects. |
||||
// if ((serverStatus & ServerStatusFlags.LastRowSent) != 0) |
||||
// { |
||||
// serverStatus &= ~ServerStatusFlags.LastRowSent; |
||||
// commandResults.Remove(lastCommandResult); |
||||
// } |
||||
} |
||||
} |
||||
|
||||
private void ReadEOF() |
||||
{ |
||||
packet = stream.ReadPacket(); |
||||
CheckEOF(); |
||||
} |
||||
|
||||
public int PrepareStatement(string sql, ref MySqlField[] parameters) |
||||
{ |
||||
//TODO: check this |
||||
//ClearFetchedRow(); |
||||
|
||||
packet.Length = sql.Length*4 + 5; |
||||
byte[] buffer = packet.Buffer; |
||||
int len = Encoding.GetBytes(sql, 0, sql.Length, packet.Buffer, 5); |
||||
packet.Position = len + 5; |
||||
buffer[4] = (byte)DBCmd.PREPARE; |
||||
ExecutePacket(packet); |
||||
|
||||
packet = stream.ReadPacket(); |
||||
|
||||
int marker = packet.ReadByte(); |
||||
if (marker != 0) |
||||
throw new MySqlException("Expected prepared statement marker"); |
||||
|
||||
int statementId = packet.ReadInteger(4); |
||||
int numCols = packet.ReadInteger(2); |
||||
int numParams = packet.ReadInteger(2); |
||||
//TODO: find out what this is needed for |
||||
packet.ReadInteger(3); |
||||
if (numParams > 0) |
||||
{ |
||||
parameters = owner.GetColumns(numParams); |
||||
// we set the encoding for each parameter back to our connection encoding |
||||
// since we can't trust what is coming back from the server |
||||
for (int i = 0; i < parameters.Length; i++) |
||||
parameters[i].Encoding = Encoding; |
||||
} |
||||
|
||||
if (numCols > 0) |
||||
{ |
||||
while (numCols-- > 0) |
||||
{ |
||||
packet = stream.ReadPacket(); |
||||
//TODO: handle streaming packets |
||||
} |
||||
|
||||
ReadEOF(); |
||||
} |
||||
|
||||
return statementId; |
||||
} |
||||
|
||||
// private void ClearFetchedRow() |
||||
// { |
||||
// if (lastCommandResult == 0) return; |
||||
|
||||
//TODO |
||||
/* CommandResult result = (CommandResult)commandResults[lastCommandResult]; |
||||
result.ReadRemainingColumns(); |
||||
|
||||
stream.OpenPacket(); |
||||
if (! stream.IsLastPacket) |
||||
throw new MySqlException("Cursor reading out of sync"); |
||||
|
||||
ReadEOF(false); |
||||
lastCommandResult = 0;*/ |
||||
// } |
||||
|
||||
/// <summary> |
||||
/// FetchDataRow is the method that the data reader calls to see if there is another |
||||
/// row to fetch. In the non-prepared mode, it will simply read the next data packet. |
||||
/// In the prepared mode (statementId > 0), it will |
||||
/// </summary> |
||||
public bool FetchDataRow(int statementId, int columns) |
||||
{ |
||||
/* ClearFetchedRow(); |
||||
|
||||
if (!commandResults.ContainsKey(statementId)) return false; |
||||
|
||||
if ( (serverStatus & ServerStatusFlags.LastRowSent) != 0) |
||||
return false; |
||||
|
||||
stream.StartPacket(9, true); |
||||
stream.WriteByte((byte)DBCmd.FETCH); |
||||
stream.WriteInteger(statementId, 4); |
||||
stream.WriteInteger(1, 4); |
||||
stream.Flush(); |
||||
|
||||
lastCommandResult = statementId; |
||||
*/ |
||||
packet = stream.ReadPacket(); |
||||
if (packet.IsLastPacket) |
||||
{ |
||||
CheckEOF(); |
||||
return false; |
||||
} |
||||
nullMap = null; |
||||
if (statementId > 0) |
||||
ReadNullMap(columns); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public void CloseStatement(int statementId) |
||||
{ |
||||
packet.Clear(); |
||||
packet.WriteByte((byte)DBCmd.CLOSE_STMT); |
||||
packet.WriteInteger((long)statementId, 4); |
||||
stream.SequenceByte = 0; |
||||
stream.SendPacket(packet); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Execution timeout, in milliseconds. When the accumulated time for network IO exceeds this value |
||||
/// TimeoutException is thrown. This timeout needs to be reset for every new command |
||||
/// </summary> |
||||
/// |
||||
public void ResetTimeout(int timeout) |
||||
{ |
||||
if (stream != null) |
||||
stream.ResetTimeout(timeout); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,88 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Diagnostics; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
internal class PerformanceMonitor |
||||
{ |
||||
private MySqlConnection connection; |
||||
private static PerformanceCounter procedureHardQueries; |
||||
private static PerformanceCounter procedureSoftQueries; |
||||
|
||||
public PerformanceMonitor(MySqlConnection connection) |
||||
{ |
||||
this.connection = connection; |
||||
|
||||
string categoryName = Resources.PerfMonCategoryName; |
||||
|
||||
if (connection.Settings.UsePerformanceMonitor && procedureHardQueries == null) |
||||
{ |
||||
try |
||||
{ |
||||
procedureHardQueries = new PerformanceCounter(categoryName, |
||||
"HardProcedureQueries", false); |
||||
procedureSoftQueries = new PerformanceCounter(categoryName, |
||||
"SoftProcedureQueries", false); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
MySqlTrace.LogError(connection.ServerThread, ex.Message); |
||||
} |
||||
} |
||||
} |
||||
|
||||
#if DEBUG |
||||
private void EnsurePerfCategoryExist() |
||||
{ |
||||
CounterCreationDataCollection ccdc = new CounterCreationDataCollection(); |
||||
CounterCreationData ccd = new CounterCreationData(); |
||||
ccd.CounterType = PerformanceCounterType.NumberOfItems32; |
||||
ccd.CounterName = "HardProcedureQueries"; |
||||
ccdc.Add(ccd); |
||||
|
||||
ccd = new CounterCreationData(); |
||||
ccd.CounterType = PerformanceCounterType.NumberOfItems32; |
||||
ccd.CounterName = "SoftProcedureQueries"; |
||||
ccdc.Add(ccd); |
||||
|
||||
if (!PerformanceCounterCategory.Exists(Resources.PerfMonCategoryName)) |
||||
PerformanceCounterCategory.Create(Resources.PerfMonCategoryName, null, ccdc); |
||||
} |
||||
#endif |
||||
|
||||
public void AddHardProcedureQuery() |
||||
{ |
||||
if (!connection.Settings.UsePerformanceMonitor || |
||||
procedureHardQueries == null) return; |
||||
procedureHardQueries.Increment(); |
||||
} |
||||
|
||||
public void AddSoftProcedureQuery() |
||||
{ |
||||
if (!connection.Settings.UsePerformanceMonitor || |
||||
procedureSoftQueries == null) return; |
||||
procedureSoftQueries.Increment(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,211 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Text; |
||||
using System.Collections.Generic; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using System.Data; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for PreparedStatement. |
||||
/// </summary> |
||||
internal class PreparableStatement : Statement |
||||
{ |
||||
private int executionCount; |
||||
private int statementId; |
||||
BitArray nullMap; |
||||
List<MySqlParameter> parametersToSend = new List<MySqlParameter>(); |
||||
MySqlPacket packet; |
||||
int dataPosition; |
||||
int nullMapPosition; |
||||
|
||||
public PreparableStatement(MySqlCommand command, string text) |
||||
: base(command, text) |
||||
{ |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public int ExecutionCount |
||||
{ |
||||
get { return executionCount; } |
||||
set { executionCount = value; } |
||||
} |
||||
|
||||
public bool IsPrepared |
||||
{ |
||||
get { return statementId > 0; } |
||||
} |
||||
|
||||
public int StatementId |
||||
{ |
||||
get { return statementId; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public virtual void Prepare() |
||||
{ |
||||
// strip out names from parameter markers |
||||
string text; |
||||
List<string> parameter_names = PrepareCommandText(out text); |
||||
|
||||
// ask our connection to send the prepare command |
||||
MySqlField[] paramList = null; |
||||
statementId = Driver.PrepareStatement(text, ref paramList); |
||||
|
||||
// now we need to assign our field names since we stripped them out |
||||
// for the prepare |
||||
for (int i = 0; i < parameter_names.Count; i++) |
||||
{ |
||||
//paramList[i].ColumnName = (string) parameter_names[i]; |
||||
string parameterName = (string)parameter_names[i]; |
||||
int index = Parameters.IndexOf(parameterName); |
||||
if (index == -1) |
||||
throw new InvalidOperationException( |
||||
String.Format(Resources.ParameterNotFoundDuringPrepare, parameterName)); |
||||
MySqlParameter p = Parameters[index]; |
||||
p.Encoding = paramList[i].Encoding; |
||||
parametersToSend.Add(p); |
||||
} |
||||
|
||||
// now prepare our null map |
||||
int numNullBytes = 0; |
||||
if (paramList != null && paramList.Length > 0) |
||||
{ |
||||
nullMap = new BitArray(paramList.Length); |
||||
numNullBytes = (nullMap.Count + 7) / 8; |
||||
} |
||||
|
||||
packet = new MySqlPacket(Driver.Encoding); |
||||
|
||||
// write out some values that do not change run to run |
||||
packet.WriteByte(0); |
||||
packet.WriteInteger(statementId, 4); |
||||
packet.WriteByte((byte)0); // flags; always 0 for 4.1 |
||||
packet.WriteInteger(1, 4); // interation count; 1 for 4.1 |
||||
nullMapPosition = packet.Position; |
||||
packet.Position += numNullBytes; // leave room for our null map |
||||
packet.WriteByte(1); // rebound flag |
||||
// write out the parameter types |
||||
foreach (MySqlParameter p in parametersToSend) |
||||
packet.WriteInteger(p.GetPSType(), 2); |
||||
dataPosition = packet.Position; |
||||
} |
||||
|
||||
public override void Execute() |
||||
{ |
||||
// if we are not prepared, then call down to our base |
||||
if (!IsPrepared) |
||||
{ |
||||
base.Execute(); |
||||
return; |
||||
} |
||||
|
||||
//TODO: support long data here |
||||
// create our null bitmap |
||||
|
||||
// we check this because Mono doesn't ignore the case where nullMapBytes |
||||
// is zero length. |
||||
// if (nullMapBytes.Length > 0) |
||||
// { |
||||
// byte[] bits = packet.Buffer; |
||||
// nullMap.CopyTo(bits, |
||||
// nullMap.CopyTo(nullMapBytes, 0); |
||||
|
||||
// start constructing our packet |
||||
// if (Parameters.Count > 0) |
||||
// nullMap.CopyTo(packet.Buffer, nullMapPosition); |
||||
//if (parameters != null && parameters.Count > 0) |
||||
//else |
||||
// packet.WriteByte( 0 ); |
||||
//TODO: only send rebound if parms change |
||||
|
||||
// now write out all non-null values |
||||
packet.Position = dataPosition; |
||||
for (int i = 0; i < parametersToSend.Count; i++) |
||||
{ |
||||
MySqlParameter p = parametersToSend[i]; |
||||
nullMap[i] = (p.Value == DBNull.Value || p.Value == null) || |
||||
p.Direction == ParameterDirection.Output; |
||||
if (nullMap[i]) continue; |
||||
packet.Encoding = p.Encoding; |
||||
p.Serialize(packet, true, Connection.Settings); |
||||
} |
||||
if (nullMap != null) |
||||
nullMap.CopyTo(packet.Buffer, nullMapPosition); |
||||
|
||||
executionCount++; |
||||
|
||||
Driver.ExecuteStatement(packet); |
||||
} |
||||
|
||||
public override bool ExecuteNext() |
||||
{ |
||||
if (!IsPrepared) |
||||
return base.ExecuteNext(); |
||||
return false; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Prepares CommandText for use with the Prepare method |
||||
/// </summary> |
||||
/// <returns>Command text stripped of all paramter names</returns> |
||||
/// <remarks> |
||||
/// Takes the output of TokenizeSql and creates a single string of SQL |
||||
/// that only contains '?' markers for each parameter. It also creates |
||||
/// the parameterMap array list that includes all the paramter names in the |
||||
/// order they appeared in the SQL |
||||
/// </remarks> |
||||
private List<string> PrepareCommandText(out string stripped_sql) |
||||
{ |
||||
StringBuilder newSQL = new StringBuilder(); |
||||
List<string> parameterMap = new List<string>(); |
||||
|
||||
int startPos = 0; |
||||
string sql = ResolvedCommandText; |
||||
MySqlTokenizer tokenizer = new MySqlTokenizer(sql); |
||||
string parameter = tokenizer.NextParameter(); |
||||
while (parameter != null) |
||||
{ |
||||
newSQL.Append(sql.Substring(startPos, tokenizer.StartIndex - startPos)); |
||||
newSQL.Append("?"); |
||||
parameterMap.Add(parameter); |
||||
startPos = tokenizer.StopIndex; |
||||
parameter = tokenizer.NextParameter(); |
||||
} |
||||
newSQL.Append(sql.Substring(startPos)); |
||||
stripped_sql = newSQL.ToString(); |
||||
return parameterMap; |
||||
} |
||||
|
||||
public virtual void CloseStatement() |
||||
{ |
||||
if (!IsPrepared) return; |
||||
|
||||
Driver.CloseStatement(statementId); |
||||
statementId = 0; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,137 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Data; |
||||
using System.Collections.Generic; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using System.Diagnostics; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
internal class ProcedureCache |
||||
{ |
||||
private Hashtable procHash; |
||||
private Queue<int> hashQueue; |
||||
private int maxSize; |
||||
|
||||
public ProcedureCache(int size) |
||||
{ |
||||
maxSize = size; |
||||
hashQueue = new Queue<int>(maxSize); |
||||
procHash = new Hashtable(maxSize); |
||||
} |
||||
|
||||
public DataSet GetProcedure(MySqlConnection conn, string spName) |
||||
{ |
||||
int hash = spName.GetHashCode(); |
||||
|
||||
DataSet ds = null; |
||||
lock (procHash.SyncRoot) |
||||
{ |
||||
ds = (DataSet)procHash[hash]; |
||||
} |
||||
if (ds == null) |
||||
{ |
||||
ds = AddNew(conn, spName); |
||||
#if !CF |
||||
conn.PerfMonitor.AddHardProcedureQuery(); |
||||
#endif |
||||
MySqlTrace.LogInformation(conn.ServerThread, |
||||
String.Format(Resources.HardProcQuery, spName)); |
||||
} |
||||
else |
||||
{ |
||||
#if !CF |
||||
conn.PerfMonitor.AddSoftProcedureQuery(); |
||||
#endif |
||||
MySqlTrace.LogInformation(conn.ServerThread, |
||||
String.Format(Resources.SoftProcQuery, spName)); |
||||
} |
||||
return ds; |
||||
} |
||||
|
||||
private DataSet AddNew(MySqlConnection connection, string spName) |
||||
{ |
||||
DataSet procData = GetProcData(connection, spName); |
||||
if (maxSize > 0) |
||||
{ |
||||
int hash = spName.GetHashCode(); |
||||
lock (procHash.SyncRoot) |
||||
{ |
||||
if (procHash.Keys.Count >= maxSize) |
||||
TrimHash(); |
||||
if (!procHash.ContainsKey(hash)) |
||||
{ |
||||
procHash[hash] = procData; |
||||
hashQueue.Enqueue(hash); |
||||
} |
||||
} |
||||
} |
||||
return procData; |
||||
} |
||||
|
||||
private void TrimHash() |
||||
{ |
||||
int oldestHash = hashQueue.Dequeue(); |
||||
procHash.Remove(oldestHash); |
||||
} |
||||
|
||||
private static DataSet GetProcData(MySqlConnection connection, string spName) |
||||
{ |
||||
string schema = String.Empty; |
||||
string name = spName; |
||||
|
||||
int dotIndex = spName.IndexOf("."); |
||||
if (dotIndex != -1) |
||||
{ |
||||
schema = spName.Substring(0, dotIndex); |
||||
name = spName.Substring(dotIndex + 1, spName.Length - dotIndex - 1); |
||||
} |
||||
|
||||
string[] restrictions = new string[4]; |
||||
restrictions[1] = schema.Length > 0 ? schema : connection.CurrentDatabase(); |
||||
restrictions[2] = name; |
||||
DataTable procTable = connection.GetSchema("procedures", restrictions); |
||||
if (procTable.Rows.Count > 1) |
||||
throw new MySqlException(Resources.ProcAndFuncSameName); |
||||
if (procTable.Rows.Count == 0) |
||||
throw new MySqlException(String.Format(Resources.InvalidProcName, name, schema)); |
||||
|
||||
DataSet ds = new DataSet(); |
||||
ds.Tables.Add(procTable); |
||||
|
||||
// we don't use GetSchema here because that would cause another |
||||
// query of procedures and we don't need that since we already |
||||
// know the procedure we care about. |
||||
ISSchemaProvider isp = new ISSchemaProvider(connection); |
||||
string[] rest = isp.CleanRestrictions(restrictions); |
||||
try |
||||
{ |
||||
DataTable parametersTable = isp.GetProcedureParameters(rest, procTable); |
||||
ds.Tables.Add(parametersTable); |
||||
} |
||||
catch (Exception) { } |
||||
|
||||
return ds; |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,215 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.IO; |
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
internal abstract class Statement |
||||
{ |
||||
protected MySqlCommand command; |
||||
protected string commandText; |
||||
private ArrayList buffers; |
||||
|
||||
private Statement(MySqlCommand cmd) |
||||
{ |
||||
command = cmd; |
||||
buffers = new ArrayList(); |
||||
} |
||||
|
||||
public Statement(MySqlCommand cmd, string text) : this(cmd) |
||||
{ |
||||
commandText = text; |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public virtual string ResolvedCommandText |
||||
{ |
||||
get { return commandText; } |
||||
} |
||||
|
||||
protected Driver Driver |
||||
{ |
||||
get { return command.Connection.driver; } |
||||
} |
||||
|
||||
protected MySqlConnection Connection |
||||
{ |
||||
get { return command.Connection; } |
||||
} |
||||
|
||||
protected MySqlParameterCollection Parameters |
||||
{ |
||||
get { return command.Parameters; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public virtual void Close(MySqlDataReader reader) |
||||
{ |
||||
} |
||||
|
||||
public virtual void Resolve(bool preparing) |
||||
{ |
||||
} |
||||
|
||||
public virtual void Execute() |
||||
{ |
||||
// we keep a reference to this until we are done |
||||
BindParameters(); |
||||
ExecuteNext(); |
||||
} |
||||
|
||||
public virtual bool ExecuteNext() |
||||
{ |
||||
if (buffers.Count == 0) |
||||
return false; |
||||
|
||||
MySqlPacket packet = (MySqlPacket)buffers[0]; |
||||
//MemoryStream ms = stream.InternalBuffer; |
||||
Driver.SendQuery(packet); |
||||
buffers.RemoveAt(0); |
||||
return true; |
||||
} |
||||
|
||||
protected virtual void BindParameters() |
||||
{ |
||||
MySqlParameterCollection parameters = command.Parameters; |
||||
int index = 0; |
||||
|
||||
while (true) |
||||
{ |
||||
InternalBindParameters(ResolvedCommandText, parameters, null); |
||||
|
||||
// if we are not batching, then we are done. This is only really relevant the |
||||
// first time through |
||||
if (command.Batch == null) return; |
||||
while (index < command.Batch.Count) |
||||
{ |
||||
MySqlCommand batchedCmd = command.Batch[index++]; |
||||
MySqlPacket packet = (MySqlPacket)buffers[buffers.Count - 1]; |
||||
|
||||
// now we make a guess if this statement will fit in our current stream |
||||
long estimatedCmdSize = batchedCmd.EstimatedSize(); |
||||
if (((packet.Length-4) + estimatedCmdSize) > Connection.driver.MaxPacketSize) |
||||
{ |
||||
// it won't, so we setup to start a new run from here |
||||
parameters = batchedCmd.Parameters; |
||||
break; |
||||
} |
||||
|
||||
// looks like we might have room for it so we remember the current end of the stream |
||||
buffers.RemoveAt(buffers.Count - 1); |
||||
//long originalLength = packet.Length - 4; |
||||
|
||||
// and attempt to stream the next command |
||||
string text = batchedCmd.BatchableCommandText; |
||||
if (text.StartsWith("(")) |
||||
packet.WriteStringNoNull(", "); |
||||
else |
||||
packet.WriteStringNoNull("; "); |
||||
InternalBindParameters(text, batchedCmd.Parameters, packet); |
||||
if ((packet.Length-4) > Connection.driver.MaxPacketSize) |
||||
{ |
||||
//TODO |
||||
//stream.InternalBuffer.SetLength(originalLength); |
||||
parameters = batchedCmd.Parameters; |
||||
break; |
||||
} |
||||
} |
||||
if (index == command.Batch.Count) |
||||
return; |
||||
} |
||||
} |
||||
|
||||
private void InternalBindParameters(string sql, MySqlParameterCollection parameters, |
||||
MySqlPacket packet) |
||||
{ |
||||
if (packet == null) |
||||
{ |
||||
packet = new MySqlPacket(Driver.Encoding); |
||||
packet.Version = Driver.Version; |
||||
packet.WriteByte(0); |
||||
} |
||||
|
||||
int startPos = 0; |
||||
MySqlTokenizer tokenizer = new MySqlTokenizer(sql); |
||||
tokenizer.ReturnComments = true; |
||||
string parameter = tokenizer.NextParameter(); |
||||
while (parameter != null) |
||||
{ |
||||
packet.WriteStringNoNull(sql.Substring(startPos, tokenizer.StartIndex - startPos)); |
||||
bool serialized = SerializeParameter(parameters, packet, parameter); |
||||
startPos = tokenizer.StopIndex; |
||||
if (!serialized) |
||||
startPos = tokenizer.StartIndex; |
||||
parameter = tokenizer.NextParameter(); |
||||
} |
||||
packet.WriteStringNoNull(sql.Substring(startPos)); |
||||
buffers.Add(packet); |
||||
} |
||||
|
||||
protected virtual bool ShouldIgnoreMissingParameter(string parameterName) |
||||
{ |
||||
if (Connection.Settings.AllowUserVariables) |
||||
return true; |
||||
if (parameterName.StartsWith("@" +StoredProcedure.ParameterPrefix)) |
||||
return true; |
||||
if (parameterName.Length > 1 && |
||||
(parameterName[1] == '`' || parameterName[1] == '\'')) |
||||
return true; |
||||
return false; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Serializes the given parameter to the given memory stream |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// <para>This method is called by PrepareSqlBuffers to convert the given |
||||
/// parameter to bytes and write those bytes to the given memory stream. |
||||
/// </para> |
||||
/// </remarks> |
||||
/// <returns>True if the parameter was successfully serialized, false otherwise.</returns> |
||||
private bool SerializeParameter(MySqlParameterCollection parameters, |
||||
MySqlPacket packet, string parmName) |
||||
{ |
||||
MySqlParameter parameter = parameters.GetParameterFlexible(parmName, false); |
||||
if (parameter == null) |
||||
{ |
||||
// if we are allowing user variables and the parameter name starts with @ |
||||
// then we can't throw an exception |
||||
if (parmName.StartsWith("@") && ShouldIgnoreMissingParameter(parmName)) |
||||
return false; |
||||
throw new MySqlException( |
||||
String.Format(Resources.ParameterMustBeDefined, parmName)); |
||||
} |
||||
parameter.Serialize(packet, false, Connection.Settings); |
||||
return true; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,289 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.Globalization; |
||||
using System.Text; |
||||
using MySql.Data.Types; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for StoredProcedure. |
||||
/// </summary> |
||||
internal class StoredProcedure : PreparableStatement |
||||
{ |
||||
private string outSelect; |
||||
private DataTable parametersTable; |
||||
private string resolvedCommandText; |
||||
|
||||
// Prefix used for to generate inout or output parameters names |
||||
internal const string ParameterPrefix = "_cnet_param_"; |
||||
|
||||
public StoredProcedure(MySqlCommand cmd, string text) |
||||
: base(cmd, text) |
||||
{ |
||||
} |
||||
|
||||
private string GetReturnParameter() |
||||
{ |
||||
if (Parameters != null) |
||||
foreach (MySqlParameter p in Parameters) |
||||
if (p.Direction == ParameterDirection.ReturnValue) |
||||
return p.ParameterName.Substring(1); |
||||
return null; |
||||
} |
||||
|
||||
public override string ResolvedCommandText |
||||
{ |
||||
get { return resolvedCommandText; } |
||||
} |
||||
|
||||
private DataSet GetParameters(string procName) |
||||
{ |
||||
// if we can use mysql.proc, then do so |
||||
//if (Connection.Settings.UseProcedureBodies) |
||||
DataSet ds = Connection.ProcedureCache.GetProcedure(Connection, procName); |
||||
|
||||
if(ds.Tables.Count == 2) |
||||
{ |
||||
// if we got our parameters and our user says it is ok to use proc bodies |
||||
// then just return them |
||||
if (Connection.Settings.UseProcedureBodies) return ds; |
||||
|
||||
// we got the parameters, but ignore them. |
||||
if(ds.Tables.Contains("Procedure Parameters")) |
||||
ds.Tables.Remove("Procedure Parameters"); |
||||
} |
||||
|
||||
// we were not able to retrieve parameter data so we have to make do by |
||||
// adding the parameters from the command object to our table |
||||
// we use an internal method to create our procedure parameters table. |
||||
ISSchemaProvider sp = new ISSchemaProvider(Connection); |
||||
DataTable pTable = sp.CreateParametersTable(); |
||||
ds.Tables.Add(pTable); |
||||
|
||||
// now we run through the parameters that were set and fill in the parameters table |
||||
// the best we can |
||||
int pos = 1; |
||||
foreach (MySqlParameter p in command.Parameters) |
||||
{ |
||||
// in this mode, all parameters must have their type set |
||||
if (!p.TypeHasBeenSet) |
||||
throw new InvalidOperationException(Resources.NoBodiesAndTypeNotSet); |
||||
|
||||
DataRow row = pTable.NewRow(); |
||||
row["PARAMETER_NAME"] = p.ParameterName; |
||||
row["PARAMETER_MODE"] = "IN"; |
||||
if (p.Direction == ParameterDirection.InputOutput) |
||||
row["PARAMETER_MODE"] = "INOUT"; |
||||
else if (p.Direction == ParameterDirection.Output) |
||||
row["PARAMETER_MODE"] = "OUT"; |
||||
else if (p.Direction == ParameterDirection.ReturnValue) |
||||
{ |
||||
row["PARAMETER_MODE"] = "OUT"; |
||||
row["ORDINAL_POSITION"] = 0; |
||||
} |
||||
else |
||||
row["ORDINAL_POSITION"] = pos++; |
||||
pTable.Rows.Add(row); |
||||
} |
||||
return ds; |
||||
} |
||||
|
||||
public static string GetFlags(string dtd) |
||||
{ |
||||
int x = dtd.Length - 1; |
||||
while (x > 0 && (Char.IsLetterOrDigit(dtd[x]) || dtd[x] == ' ')) |
||||
x--; |
||||
return dtd.Substring(x).ToUpper(CultureInfo.InvariantCulture); |
||||
} |
||||
|
||||
private string FixProcedureName(string name) |
||||
{ |
||||
string[] parts = name.Split('.'); |
||||
for (int i = 0; i < parts.Length; i++) |
||||
if (!parts[i].StartsWith("`")) |
||||
parts[i] = String.Format("`{0}`", parts[i]); |
||||
if (parts.Length == 1) return parts[0]; |
||||
return String.Format("{0}.{1}", parts[0], parts[1]); |
||||
} |
||||
|
||||
private MySqlParameter GetAndFixParameter(DataRow param, bool realAsFloat, string returnParameter) |
||||
{ |
||||
string mode = (string)param["PARAMETER_MODE"]; |
||||
string pName = (string)param["PARAMETER_NAME"]; |
||||
|
||||
if (param["ORDINAL_POSITION"].Equals(0)) |
||||
pName = returnParameter; |
||||
|
||||
if (pName == null) return null; |
||||
|
||||
// make sure the parameters given to us have an appropriate |
||||
// type set if it's not already |
||||
MySqlParameter p = command.Parameters.GetParameterFlexible(pName, true); |
||||
if (!p.TypeHasBeenSet) |
||||
{ |
||||
string datatype = (string)param["DATA_TYPE"]; |
||||
bool unsigned = GetFlags(param["DTD_IDENTIFIER"].ToString()).IndexOf("UNSIGNED") != -1; |
||||
p.MySqlDbType = MetaData.NameToType(datatype, unsigned, realAsFloat, Connection); |
||||
} |
||||
return p; |
||||
} |
||||
|
||||
public override void Resolve(bool preparing) |
||||
{ |
||||
// check to see if we are already resolved |
||||
if (resolvedCommandText != null) return; |
||||
|
||||
// first retrieve the procedure definition from our |
||||
// procedure cache |
||||
string spName = commandText; |
||||
if (spName.IndexOf(".") == -1 && !String.IsNullOrEmpty(Connection.Database)) |
||||
spName = Connection.Database + "." + spName; |
||||
spName = FixProcedureName(spName); |
||||
|
||||
DataSet ds = GetParameters(spName); |
||||
|
||||
DataTable procTable = ds.Tables["procedures"]; |
||||
parametersTable = ds.Tables["procedure parameters"]; |
||||
|
||||
if (procTable.Rows.Count == 0) |
||||
throw new InvalidOperationException(String.Format(Resources.RoutineNotFound, spName)); |
||||
|
||||
bool realAsFloat = procTable.Rows[0]["SQL_MODE"].ToString().IndexOf("REAL_AS_FLOAT") != -1; |
||||
StringBuilder sqlStr = new StringBuilder(); |
||||
StringBuilder outSql = new StringBuilder(); |
||||
string sqlDelimiter = ""; |
||||
string outDelimiter = ""; |
||||
|
||||
string retParm = GetReturnParameter(); |
||||
foreach (DataRow param in parametersTable.Rows) |
||||
{ |
||||
MySqlParameter p = GetAndFixParameter(param, realAsFloat, retParm); |
||||
if (p == null) continue; |
||||
|
||||
if (param["ORDINAL_POSITION"].Equals(0)) |
||||
continue; |
||||
|
||||
string baseName = p.ParameterName; |
||||
string pName = baseName; |
||||
if (baseName.StartsWith("@") || baseName.StartsWith("?")) |
||||
baseName = baseName.Substring(1); |
||||
else |
||||
pName = "@" + pName; |
||||
|
||||
string inputVar = pName; |
||||
if (p.Direction != ParameterDirection.Input && |
||||
!(Connection.driver.SupportsOutputParameters || preparing)) |
||||
{ |
||||
// set a user variable to our current value |
||||
string sql = String.Format("SET @{0}{1}={2}", ParameterPrefix, baseName, pName); |
||||
MySqlCommand cmd = new MySqlCommand(sql, Connection); |
||||
|
||||
cmd.Parameters.Add(p); |
||||
cmd.ExecuteNonQuery(); |
||||
|
||||
inputVar = String.Format("@{0}{1}", ParameterPrefix, baseName); |
||||
|
||||
outSql.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", outDelimiter, inputVar); |
||||
outDelimiter = ", "; |
||||
} |
||||
sqlStr.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", sqlDelimiter, inputVar); |
||||
sqlDelimiter = ", "; |
||||
} |
||||
|
||||
string sqlCmd = sqlStr.ToString().TrimEnd(' ', ','); |
||||
outSelect = outSql.ToString().TrimEnd(' ', ','); |
||||
|
||||
if (procTable.Rows[0]["ROUTINE_TYPE"].Equals("PROCEDURE")) |
||||
sqlCmd = String.Format("call {0} ({1})", spName, sqlCmd); |
||||
else |
||||
{ |
||||
if (retParm == null) |
||||
retParm = ParameterPrefix + "dummy"; |
||||
else |
||||
outSelect = String.Format("@{0}{1}", ParameterPrefix, retParm); |
||||
sqlCmd = String.Format("SET @{0}{1}={2}({3})", ParameterPrefix, retParm, spName, sqlCmd); |
||||
} |
||||
|
||||
resolvedCommandText = sqlCmd; |
||||
} |
||||
|
||||
private MySqlDataReader GetHackedOuputParameters() |
||||
{ |
||||
if (outSelect.Length == 0) return null; |
||||
|
||||
MySqlCommand cmd = new MySqlCommand("SELECT " + outSelect, Connection); |
||||
|
||||
MySqlDataReader reader = cmd.ExecuteReader(); |
||||
// since MySQL likes to return user variables as strings |
||||
// we reset the types of the readers internal value objects |
||||
// this will allow those value objects to parse the string based |
||||
// return values |
||||
ResultSet results = reader.ResultSet; |
||||
for (int i = 0; i < reader.FieldCount; i++) |
||||
{ |
||||
string fieldName = reader.GetName(i); |
||||
fieldName = fieldName.Remove(0, ParameterPrefix.Length + 1); |
||||
MySqlParameter parameter = Parameters.GetParameterFlexible(fieldName, true); |
||||
results.SetValueObject(i, MySqlField.GetIMySqlValue(parameter.MySqlDbType)); |
||||
} |
||||
if (!reader.Read()) |
||||
{ |
||||
reader.Close(); |
||||
return null; |
||||
} |
||||
return reader; |
||||
} |
||||
|
||||
public override void Close(MySqlDataReader reader) |
||||
{ |
||||
base.Close(reader); |
||||
|
||||
ResultSet rs = reader.ResultSet; |
||||
// if our closing reader doesn't have output parameters then we may have to |
||||
// use the user variable hack |
||||
if (rs == null || !rs.IsOutputParameters) |
||||
{ |
||||
MySqlDataReader rdr = GetHackedOuputParameters(); |
||||
if (rdr == null) return; |
||||
reader = rdr; |
||||
} |
||||
|
||||
using (reader) |
||||
{ |
||||
string prefix = "@" + ParameterPrefix; |
||||
|
||||
for (int i = 0; i < reader.FieldCount; i++) |
||||
{ |
||||
string fieldName = reader.GetName(i); |
||||
if (fieldName.StartsWith(prefix)) |
||||
fieldName = fieldName.Remove(0, prefix.Length); |
||||
MySqlParameter parameter = Parameters.GetParameterFlexible(fieldName, true); |
||||
parameter.Value = reader.GetValue(i); |
||||
} |
||||
reader.Close(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,137 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Globalization; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal class MetaData |
||||
{ |
||||
public static bool IsNumericType(string typename) |
||||
{ |
||||
string lowerType = typename.ToLower(CultureInfo.InvariantCulture); |
||||
switch (lowerType) |
||||
{ |
||||
case "int": |
||||
case "integer": |
||||
case "numeric": |
||||
case "decimal": |
||||
case "dec": |
||||
case "fixed": |
||||
case "tinyint": |
||||
case "mediumint": |
||||
case "bigint": |
||||
case "real": |
||||
case "double": |
||||
case "float": |
||||
case "serial": |
||||
case "smallint": return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public static bool SupportScale(string typename) |
||||
{ |
||||
string lowerType = typename.ToLower(CultureInfo.InvariantCulture); |
||||
switch (lowerType) |
||||
{ |
||||
case "numeric": |
||||
case "decimal": |
||||
case "dec": |
||||
case "real": return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public static MySqlDbType NameToType(string typeName, bool unsigned, |
||||
bool realAsFloat, MySqlConnection connection) |
||||
{ |
||||
switch (typeName.ToUpper(CultureInfo.InvariantCulture)) |
||||
{ |
||||
case "CHAR": return MySqlDbType.String; |
||||
case "VARCHAR": return MySqlDbType.VarChar; |
||||
case "DATE": return MySqlDbType.Date; |
||||
case "DATETIME": return MySqlDbType.DateTime; |
||||
case "NUMERIC": |
||||
case "DECIMAL": |
||||
case "DEC": |
||||
case "FIXED": |
||||
if (connection.driver.Version.isAtLeast(5, 0, 3)) |
||||
return MySqlDbType.NewDecimal; |
||||
else |
||||
return MySqlDbType.Decimal; |
||||
case "YEAR": |
||||
return MySqlDbType.Year; |
||||
case "TIME": |
||||
return MySqlDbType.Time; |
||||
case "TIMESTAMP": |
||||
return MySqlDbType.Timestamp; |
||||
case "SET": return MySqlDbType.Set; |
||||
case "ENUM": return MySqlDbType.Enum; |
||||
case "BIT": return MySqlDbType.Bit; |
||||
|
||||
case "TINYINT": |
||||
return unsigned ? MySqlDbType.UByte : MySqlDbType.Byte; |
||||
case "BOOL": |
||||
case "BOOLEAN": |
||||
return MySqlDbType.Byte; |
||||
case "SMALLINT": |
||||
return unsigned ? MySqlDbType.UInt16 : MySqlDbType.Int16; |
||||
case "MEDIUMINT": |
||||
return unsigned ? MySqlDbType.UInt24 : MySqlDbType.Int24; |
||||
case "INT": |
||||
case "INTEGER": |
||||
return unsigned ? MySqlDbType.UInt32 : MySqlDbType.Int32; |
||||
case "SERIAL": |
||||
return MySqlDbType.UInt64; |
||||
case "BIGINT": |
||||
return unsigned ? MySqlDbType.UInt64 : MySqlDbType.Int64; |
||||
case "FLOAT": return MySqlDbType.Float; |
||||
case "DOUBLE": return MySqlDbType.Double; |
||||
case "REAL": return |
||||
realAsFloat ? MySqlDbType.Float : MySqlDbType.Double; |
||||
case "TEXT": |
||||
return MySqlDbType.Text; |
||||
case "BLOB": |
||||
return MySqlDbType.Blob; |
||||
case "LONGBLOB": |
||||
return MySqlDbType.LongBlob; |
||||
case "LONGTEXT": |
||||
return MySqlDbType.LongText; |
||||
case "MEDIUMBLOB": |
||||
return MySqlDbType.MediumBlob; |
||||
case "MEDIUMTEXT": |
||||
return MySqlDbType.MediumText; |
||||
case "TINYBLOB": |
||||
return MySqlDbType.TinyBlob; |
||||
case "TINYTEXT": |
||||
return MySqlDbType.TinyText; |
||||
case "BINARY": |
||||
return MySqlDbType.Binary; |
||||
case "VARBINARY": |
||||
return MySqlDbType.VarBinary; |
||||
} |
||||
throw new MySqlException("Unhandled type encountered"); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,226 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
|
||||
internal struct MySqlBinary : IMySqlValue |
||||
{ |
||||
private MySqlDbType type; |
||||
private byte[] mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlBinary(MySqlDbType type, bool isNull) |
||||
{ |
||||
this.type = type; |
||||
this.isNull = isNull; |
||||
mValue = null; |
||||
} |
||||
|
||||
public MySqlBinary(MySqlDbType type, byte[] val) |
||||
{ |
||||
this.type = type; |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return type; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Binary; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public byte[] Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(byte[]); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case MySqlDbType.TinyBlob: return "TINY_BLOB"; |
||||
case MySqlDbType.MediumBlob: return "MEDIUM_BLOB"; |
||||
case MySqlDbType.LongBlob: return "LONG_BLOB"; |
||||
case MySqlDbType.Blob: |
||||
default: |
||||
return "BLOB"; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
byte[] buffToWrite = (val as byte[]); |
||||
if (buffToWrite == null) |
||||
{ |
||||
char[] valAsChar = (val as Char[]); |
||||
if (valAsChar != null) |
||||
buffToWrite = packet.Encoding.GetBytes(valAsChar); |
||||
else |
||||
{ |
||||
string s = val.ToString(); |
||||
if (length == 0) |
||||
length = s.Length; |
||||
else |
||||
s = s.Substring(0, length); |
||||
buffToWrite = packet.Encoding.GetBytes(s); |
||||
} |
||||
} |
||||
|
||||
// we assume zero length means write all of the value |
||||
if (length == 0) |
||||
length = buffToWrite.Length; |
||||
|
||||
if (buffToWrite == null) |
||||
throw new MySqlException("Only byte arrays and strings can be serialized by MySqlBinary"); |
||||
|
||||
if (binary) |
||||
{ |
||||
packet.WriteLength(length); |
||||
packet.Write(buffToWrite, 0, length); |
||||
} |
||||
else |
||||
{ |
||||
if (packet.Version.isAtLeast(4, 1, 0)) |
||||
packet.WriteStringNoNull("_binary "); |
||||
|
||||
packet.WriteByte((byte)'\''); |
||||
EscapeByteArray(buffToWrite, length, packet); |
||||
packet.WriteByte((byte)'\''); |
||||
} |
||||
} |
||||
|
||||
private static void EscapeByteArray(byte[] bytes, int length, MySqlPacket packet) |
||||
{ |
||||
for (int x = 0; x < length; x++) |
||||
{ |
||||
byte b = bytes[x]; |
||||
if (b == '\0') |
||||
{ |
||||
packet.WriteByte((byte)'\\'); |
||||
packet.WriteByte((byte)'0'); |
||||
} |
||||
|
||||
else if (b == '\\' || b == '\'' || b == '\"') |
||||
{ |
||||
packet.WriteByte((byte)'\\'); |
||||
packet.WriteByte(b); |
||||
} |
||||
else |
||||
packet.WriteByte(b); |
||||
} |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
MySqlBinary b; |
||||
if (nullVal) |
||||
b = new MySqlBinary(type, true); |
||||
else |
||||
{ |
||||
if (length == -1) |
||||
length = (long)packet.ReadFieldLength(); |
||||
|
||||
byte[] newBuff = new byte[length]; |
||||
packet.Read(newBuff, 0, (int)length); |
||||
b = new MySqlBinary(type, newBuff); |
||||
} |
||||
return b; |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
int len = packet.ReadFieldLength(); |
||||
packet.Position += len; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
string[] types = new string[] { "BLOB", "TINYBLOB", "MEDIUMBLOB", "LONGBLOB", "BINARY", "VARBINARY" }; |
||||
MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.Blob, |
||||
MySqlDbType.TinyBlob, MySqlDbType.MediumBlob, MySqlDbType.LongBlob, MySqlDbType.Binary, MySqlDbType.VarBinary }; |
||||
long[] sizes = new long[] { 65535L, 255L, 16777215L, 4294967295L, 255L, 65535L }; |
||||
string[] format = new string[] { null, null, null, null, "binary({0})", "varbinary({0})" }; |
||||
string[] parms = new string[] { null, null, null, null, "length", "length" }; |
||||
|
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
for (int x = 0; x < types.Length; x++) |
||||
{ |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = types[x]; |
||||
row["ProviderDbType"] = dbtype[x]; |
||||
row["ColumnSize"] = sizes[x]; |
||||
row["CreateFormat"] = format[x]; |
||||
row["CreateParameters"] = parms[x]; |
||||
row["DataType"] = "System.Byte[]"; |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = x < 4 ? false : true; |
||||
row["IsFixedPrecisionScale"] = false; |
||||
row["IsLong"] = sizes[x] > 255; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = false; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = DBNull.Value; |
||||
row["MaximumScale"] = DBNull.Value; |
||||
row["MinimumScale"] = DBNull.Value; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = "0x"; |
||||
row["LiteralSuffix"] = DBNull.Value; |
||||
row["NativeDataType"] = DBNull.Value; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,137 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for MySqlUInt64. |
||||
/// </summary> |
||||
internal struct MySqlBit : IMySqlValue |
||||
{ |
||||
private ulong mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlBit(bool isnull) |
||||
{ |
||||
mValue = 0; |
||||
isNull = isnull; |
||||
} |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Bit; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.UInt64; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get |
||||
{ |
||||
return mValue; |
||||
} |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get |
||||
{ |
||||
return typeof(UInt64); |
||||
} |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "BIT"; } |
||||
} |
||||
|
||||
public void WriteValue(MySqlPacket packet, bool binary, object value, int length) |
||||
{ |
||||
ulong v = (value is UInt64) ? (UInt64)value : Convert.ToUInt64(value); |
||||
if (binary) |
||||
packet.WriteInteger((long)v, 8); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString()); |
||||
} |
||||
|
||||
public IMySqlValue ReadValue(MySqlPacket packet, long length, bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
if (isNull) |
||||
return this; |
||||
|
||||
if (length == -1) |
||||
length = packet.ReadFieldLength(); |
||||
|
||||
mValue = (UInt64)packet.ReadBitValue((int)length); |
||||
return this; |
||||
} |
||||
|
||||
public void SkipValue(MySqlPacket packet) |
||||
{ |
||||
int len = packet.ReadFieldLength(); |
||||
packet.Position += len; |
||||
} |
||||
|
||||
public static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "BIT"; |
||||
row["ProviderDbType"] = MySqlDbType.Bit; |
||||
row["ColumnSize"] = 64; |
||||
row["CreateFormat"] = "BIT"; |
||||
row["CreateParameters"] = DBNull.Value; ; |
||||
row["DataType"] = typeof(UInt64).ToString(); |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = false; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = DBNull.Value; |
||||
row["LiteralSuffix"] = DBNull.Value; |
||||
row["NativeDataType"] = DBNull.Value; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,171 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Globalization; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlByte : IMySqlValue |
||||
{ |
||||
private sbyte mValue; |
||||
private bool isNull; |
||||
private bool treatAsBool; |
||||
|
||||
public MySqlByte(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = 0; |
||||
treatAsBool = false; |
||||
} |
||||
|
||||
public MySqlByte(sbyte val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
treatAsBool = false; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Byte; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get |
||||
{ |
||||
if (TreatAsBoolean) |
||||
return DbType.Boolean; |
||||
return DbType.SByte; |
||||
} |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get |
||||
{ |
||||
if (TreatAsBoolean) |
||||
return Convert.ToBoolean(mValue); |
||||
return mValue; |
||||
} |
||||
} |
||||
|
||||
public sbyte Value |
||||
{ |
||||
get { return mValue; } |
||||
set { mValue = value; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get |
||||
{ |
||||
if (TreatAsBoolean) |
||||
return typeof(Boolean); |
||||
return typeof(sbyte); |
||||
} |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "TINYINT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
sbyte v = (val is sbyte) ? (sbyte)val : Convert.ToSByte(val); |
||||
if (binary) |
||||
packet.WriteByte((byte)v); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString()); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlByte(true); |
||||
|
||||
if (length == -1) |
||||
return new MySqlByte((sbyte)packet.ReadByte()); |
||||
else |
||||
{ |
||||
string s = packet.ReadString(length); |
||||
MySqlByte b = new MySqlByte(SByte.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture)); |
||||
b.TreatAsBoolean = TreatAsBoolean; |
||||
return b; |
||||
} |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.ReadByte(); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal bool TreatAsBoolean |
||||
{ |
||||
get { return treatAsBool; } |
||||
set { treatAsBool = value; } |
||||
} |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "TINYINT"; |
||||
row["ProviderDbType"] = MySqlDbType.Byte; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "TINYINT"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.SByte"; |
||||
row["IsAutoincrementable"] = true; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for MySqlConversionException. |
||||
/// </summary> |
||||
#if !CF |
||||
[Serializable] |
||||
#endif |
||||
public class MySqlConversionException : Exception |
||||
{ |
||||
/// <summary>Ctor</summary> |
||||
public MySqlConversionException(string msg) |
||||
: base(msg) |
||||
{ |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,646 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.IO; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Globalization; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
|
||||
/// <summary> |
||||
/// |
||||
/// </summary> |
||||
public struct MySqlDateTime : IMySqlValue, IConvertible, IComparable |
||||
{ |
||||
private bool isNull; |
||||
private MySqlDbType type; |
||||
private int year, month, day, hour, minute, second; |
||||
private int millisecond; |
||||
|
||||
/// <summary> |
||||
/// Constructs a new <b>MySqlDateTime</b> object by setting the individual time properties to |
||||
/// the given values. |
||||
/// </summary> |
||||
/// <param name="year">The year to use.</param> |
||||
/// <param name="month">The month to use.</param> |
||||
/// <param name="day">The day to use.</param> |
||||
/// <param name="hour">The hour to use.</param> |
||||
/// <param name="minute">The minute to use.</param> |
||||
/// <param name="second">The second to use.</param> |
||||
public MySqlDateTime(int year, int month, int day, int hour, int minute, int second) |
||||
: this(MySqlDbType.DateTime, year, month, day, hour, minute, second) |
||||
{ |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Constructs a new <b>MySqlDateTime</b> object by using values from the given <see cref="DateTime"/> object. |
||||
/// </summary> |
||||
/// <param name="dt">The <see cref="DateTime"/> object to copy.</param> |
||||
public MySqlDateTime(DateTime dt) |
||||
: this(MySqlDbType.DateTime, dt) |
||||
{ |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Constructs a new <b>MySqlDateTime</b> object by copying the current value of the given object. |
||||
/// </summary> |
||||
/// <param name="mdt">The <b>MySqlDateTime</b> object to copy.</param> |
||||
public MySqlDateTime(MySqlDateTime mdt) |
||||
{ |
||||
year = mdt.Year; |
||||
month = mdt.Month; |
||||
day = mdt.Day; |
||||
hour = mdt.Hour; |
||||
minute = mdt.Minute; |
||||
second = mdt.Second; |
||||
millisecond = 0; |
||||
type = MySqlDbType.DateTime; |
||||
isNull = false; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Enables the contruction of a <b>MySqlDateTime</b> object by parsing a string. |
||||
/// </summary> |
||||
public MySqlDateTime(string dateTime) |
||||
: this(MySqlDateTime.Parse(dateTime)) |
||||
{ |
||||
} |
||||
|
||||
internal MySqlDateTime(MySqlDbType type, int year, int month, int day, int hour, int minute, |
||||
int second) |
||||
{ |
||||
this.isNull = false; |
||||
this.type = type; |
||||
this.year = year; |
||||
this.month = month; |
||||
this.day = day; |
||||
this.hour = hour; |
||||
this.minute = minute; |
||||
this.second = second; |
||||
this.millisecond = 0; |
||||
} |
||||
|
||||
internal MySqlDateTime(MySqlDbType type, bool isNull) |
||||
: this(type, 0, 0, 0, 0, 0, 0) |
||||
{ |
||||
this.isNull = isNull; |
||||
} |
||||
|
||||
internal MySqlDateTime(MySqlDbType type, DateTime val) |
||||
: this(type, 0, 0, 0, 0, 0, 0) |
||||
{ |
||||
this.isNull = false; |
||||
year = val.Year; |
||||
month = val.Month; |
||||
day = val.Day; |
||||
hour = val.Hour; |
||||
minute = val.Minute; |
||||
second = val.Second; |
||||
millisecond = val.Millisecond; |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
/// <summary> |
||||
/// Indicates if this object contains a value that can be represented as a DateTime |
||||
/// </summary> |
||||
public bool IsValidDateTime |
||||
{ |
||||
get |
||||
{ |
||||
return year != 0 && month != 0 && day != 0; |
||||
} |
||||
} |
||||
|
||||
/// <summary>Returns the year portion of this datetime</summary> |
||||
public int Year |
||||
{ |
||||
get { return year; } |
||||
set { year = value; } |
||||
} |
||||
|
||||
/// <summary>Returns the month portion of this datetime</summary> |
||||
public int Month |
||||
{ |
||||
get { return month; } |
||||
set { month = value; } |
||||
} |
||||
|
||||
/// <summary>Returns the day portion of this datetime</summary> |
||||
public int Day |
||||
{ |
||||
get { return day; } |
||||
set { day = value; } |
||||
} |
||||
|
||||
/// <summary>Returns the hour portion of this datetime</summary> |
||||
public int Hour |
||||
{ |
||||
get { return hour; } |
||||
set { hour = value; } |
||||
} |
||||
|
||||
/// <summary>Returns the minute portion of this datetime</summary> |
||||
public int Minute |
||||
{ |
||||
get { return minute; } |
||||
set { minute = value; } |
||||
} |
||||
|
||||
/// <summary>Returns the second portion of this datetime</summary> |
||||
public int Second |
||||
{ |
||||
get { return second; } |
||||
set { second = value; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Retrieves the millisecond value of this object. |
||||
/// </summary> |
||||
public int Millisecond |
||||
{ |
||||
get { return millisecond; } |
||||
set { millisecond = value; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
/// <summary> |
||||
/// Returns true if this datetime object has a null value |
||||
/// </summary> |
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return type; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get |
||||
{ |
||||
if (type == MySqlDbType.Date || type == MySqlDbType.Newdate) |
||||
return DbType.Date; |
||||
return DbType.DateTime; |
||||
} |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return GetDateTime(); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Retrieves the value of this <see cref="MySqlDateTime"/> as a DateTime object. |
||||
/// </summary> |
||||
public DateTime Value |
||||
{ |
||||
get { return GetDateTime(); } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(DateTime); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case MySqlDbType.Date: return "DATE"; |
||||
case MySqlDbType.Newdate: return "NEWDATE"; |
||||
case MySqlDbType.Timestamp: return "TIMESTAMP"; |
||||
} |
||||
return "DATETIME"; |
||||
} |
||||
} |
||||
|
||||
|
||||
private void SerializeText(MySqlPacket packet, MySqlDateTime value) |
||||
{ |
||||
string val = String.Empty; |
||||
|
||||
if (type == MySqlDbType.Timestamp && !packet.Version.isAtLeast(4, 1, 0)) |
||||
val = String.Format("{0:0000}{1:00}{2:00}{3:00}{4:00}{5:00}", |
||||
value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second); |
||||
else |
||||
{ |
||||
val = String.Format("{0:0000}-{1:00}-{2:00}", |
||||
value.Year, value.Month, value.Day); |
||||
if (type != MySqlDbType.Date) |
||||
val = String.Format("{0} {1:00}:{2:00}:{3:00}", val, |
||||
value.Hour, value.Minute, value.Second); |
||||
} |
||||
packet.WriteStringNoNull("'" + val + "'"); |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object value, int length) |
||||
{ |
||||
MySqlDateTime dtValue; |
||||
|
||||
string valueAsString = value as string; |
||||
|
||||
if (value is DateTime) |
||||
dtValue = new MySqlDateTime(type, (DateTime)value); |
||||
else if (valueAsString != null) |
||||
dtValue = new MySqlDateTime(type, DateTime.Parse(valueAsString, CultureInfo.CurrentCulture)); |
||||
else if (value is MySqlDateTime) |
||||
dtValue = (MySqlDateTime)value; |
||||
else |
||||
throw new MySqlException("Unable to serialize date/time value."); |
||||
|
||||
if (!binary) |
||||
{ |
||||
SerializeText(packet, dtValue); |
||||
return; |
||||
} |
||||
|
||||
if (type == MySqlDbType.Timestamp) |
||||
packet.WriteByte(11); |
||||
else |
||||
packet.WriteByte(7); |
||||
|
||||
packet.WriteInteger(dtValue.Year, 2); |
||||
packet.WriteByte((byte)dtValue.Month); |
||||
packet.WriteByte((byte)dtValue.Day); |
||||
if (type == MySqlDbType.Date) |
||||
{ |
||||
packet.WriteByte(0); |
||||
packet.WriteByte(0); |
||||
packet.WriteByte(0); |
||||
} |
||||
else |
||||
{ |
||||
packet.WriteByte((byte)dtValue.Hour); |
||||
packet.WriteByte((byte)dtValue.Minute); |
||||
packet.WriteByte((byte)dtValue.Second); |
||||
} |
||||
|
||||
if (type == MySqlDbType.Timestamp) |
||||
packet.WriteInteger(dtValue.Millisecond, 4); |
||||
} |
||||
|
||||
private MySqlDateTime Parse40Timestamp(string s) |
||||
{ |
||||
int pos = 0; |
||||
year = month = day = 1; |
||||
hour = minute = second = 0; |
||||
|
||||
if (s.Length == 14 || s.Length == 8) |
||||
{ |
||||
year = int.Parse(s.Substring(pos, 4)); |
||||
pos += 4; |
||||
} |
||||
else |
||||
{ |
||||
year = int.Parse(s.Substring(pos, 2)); |
||||
pos += 2; |
||||
if (year >= 70) |
||||
year += 1900; |
||||
else |
||||
year += 2000; |
||||
} |
||||
|
||||
if (s.Length > 2) |
||||
{ |
||||
month = int.Parse(s.Substring(pos, 2)); |
||||
pos += 2; |
||||
} |
||||
if (s.Length > 4) |
||||
{ |
||||
day = int.Parse(s.Substring(pos, 2)); |
||||
pos += 2; |
||||
} |
||||
if (s.Length > 8) |
||||
{ |
||||
hour = int.Parse(s.Substring(pos, 2)); |
||||
minute = int.Parse(s.Substring(pos + 2, 2)); |
||||
pos += 4; |
||||
} |
||||
if (s.Length > 10) |
||||
second = int.Parse(s.Substring(pos, 2)); |
||||
|
||||
return new MySqlDateTime(type, year, month, day, hour, |
||||
minute, second); |
||||
} |
||||
|
||||
static internal MySqlDateTime Parse(string s) |
||||
{ |
||||
MySqlDateTime dt = new MySqlDateTime(); |
||||
return dt.ParseMySql(s, true); |
||||
} |
||||
|
||||
static internal MySqlDateTime Parse(string s, Common.DBVersion version) |
||||
{ |
||||
MySqlDateTime dt = new MySqlDateTime(); |
||||
return dt.ParseMySql(s, version.isAtLeast(4, 1, 0)); |
||||
} |
||||
|
||||
private MySqlDateTime ParseMySql(string s, bool is41) |
||||
{ |
||||
if (type == MySqlDbType.Timestamp && !is41) |
||||
return Parse40Timestamp(s); |
||||
|
||||
string[] parts = s.Split('-', ' ', ':', '/'); |
||||
|
||||
int year = int.Parse(parts[0]); |
||||
int month = int.Parse(parts[1]); |
||||
int day = int.Parse(parts[2]); |
||||
|
||||
int hour = 0, minute = 0, second = 0; |
||||
if (parts.Length > 3) |
||||
{ |
||||
hour = int.Parse(parts[3]); |
||||
minute = int.Parse(parts[4]); |
||||
second = int.Parse(parts[5]); |
||||
} |
||||
|
||||
return new MySqlDateTime(type, year, month, day, hour, minute, second); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) return new MySqlDateTime(type, true); |
||||
|
||||
if (length >= 0) |
||||
{ |
||||
string value = packet.ReadString(length); |
||||
return ParseMySql(value, packet.Version.isAtLeast(4, 1, 0)); |
||||
} |
||||
|
||||
long bufLength = packet.ReadByte(); |
||||
int year = 0, month = 0, day = 0; |
||||
int hour = 0, minute = 0, second = 0; |
||||
|
||||
if (bufLength >= 4) |
||||
{ |
||||
year = packet.ReadInteger(2); |
||||
month = packet.ReadByte(); |
||||
day = packet.ReadByte(); |
||||
} |
||||
|
||||
if (bufLength > 4) |
||||
{ |
||||
hour = packet.ReadByte(); |
||||
minute = packet.ReadByte(); |
||||
second = packet.ReadByte(); |
||||
} |
||||
|
||||
if (bufLength > 7) |
||||
packet.ReadInteger(4); |
||||
|
||||
return new MySqlDateTime(type, year, month, day, hour, minute, second); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
int len = packet.ReadByte(); |
||||
packet.Position += len; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
/// <summary>Returns this value as a DateTime</summary> |
||||
public DateTime GetDateTime() |
||||
{ |
||||
if (!IsValidDateTime) |
||||
throw new MySqlConversionException("Unable to convert MySQL date/time value to System.DateTime"); |
||||
|
||||
return new DateTime(year, month, day, hour, minute, second); |
||||
} |
||||
|
||||
private static string FormatDateCustom(string format, int monthVal, int dayVal, int yearVal) |
||||
{ |
||||
format = format.Replace("MM", "{0:00}"); |
||||
format = format.Replace("M", "{0}"); |
||||
format = format.Replace("dd", "{1:00}"); |
||||
format = format.Replace("d", "{1}"); |
||||
format = format.Replace("yyyy", "{2:0000}"); |
||||
format = format.Replace("yy", "{3:00}"); |
||||
format = format.Replace("y", "{4:0}"); |
||||
|
||||
int year2digit = yearVal - ((yearVal / 1000) * 1000); |
||||
year2digit -= ((year2digit / 100) * 100); |
||||
int year1digit = year2digit - ((year2digit / 10) * 10); |
||||
|
||||
return String.Format(format, monthVal, dayVal, yearVal, year2digit, year1digit); |
||||
} |
||||
|
||||
/// <summary>Returns a MySQL specific string representation of this value</summary> |
||||
public override string ToString() |
||||
{ |
||||
if (this.IsValidDateTime) |
||||
{ |
||||
DateTime d = new DateTime(year, month, day, hour, minute, second); |
||||
return (type == MySqlDbType.Date) ? d.ToString("d") : d.ToString(); |
||||
} |
||||
|
||||
string dateString = FormatDateCustom( |
||||
CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern, month, day, year); |
||||
if (type == MySqlDbType.Date) |
||||
return dateString; |
||||
|
||||
DateTime dt = new DateTime(1, 2, 3, hour, minute, second); |
||||
dateString = String.Format("{0} {1}", dateString, dt.ToLongTimeString()); |
||||
return dateString; |
||||
} |
||||
|
||||
/// <summary></summary> |
||||
/// <param name="val"></param> |
||||
/// <returns></returns> |
||||
public static explicit operator DateTime(MySqlDateTime val) |
||||
{ |
||||
if (!val.IsValidDateTime) return DateTime.MinValue; |
||||
return val.GetDateTime(); |
||||
} |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
string[] types = new string[] { "DATE", "DATETIME", "TIMESTAMP" }; |
||||
MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.Date, |
||||
MySqlDbType.DateTime, MySqlDbType.Timestamp }; |
||||
|
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
for (int x = 0; x < types.Length; x++) |
||||
{ |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = types[x]; |
||||
row["ProviderDbType"] = dbtype[x]; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = types[x]; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.DateTime"; |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
|
||||
#region IConvertible Members |
||||
|
||||
ulong IConvertible.ToUInt64(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
sbyte IConvertible.ToSByte(IFormatProvider provider) |
||||
{ |
||||
// TODO: Add MySqlDateTime.ToSByte implementation |
||||
return 0; |
||||
} |
||||
|
||||
double IConvertible.ToDouble(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
DateTime IConvertible.ToDateTime(IFormatProvider provider) |
||||
{ |
||||
return this.GetDateTime(); |
||||
} |
||||
|
||||
float IConvertible.ToSingle(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
bool IConvertible.ToBoolean(IFormatProvider provider) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
int IConvertible.ToInt32(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
ushort IConvertible.ToUInt16(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
short IConvertible.ToInt16(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
string System.IConvertible.ToString(IFormatProvider provider) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
byte IConvertible.ToByte(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
char IConvertible.ToChar(IFormatProvider provider) |
||||
{ |
||||
return '\0'; |
||||
} |
||||
|
||||
long IConvertible.ToInt64(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
System.TypeCode IConvertible.GetTypeCode() |
||||
{ |
||||
return new System.TypeCode(); |
||||
} |
||||
|
||||
decimal IConvertible.ToDecimal(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
object IConvertible.ToType(Type conversionType, IFormatProvider provider) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
uint IConvertible.ToUInt32(IFormatProvider provider) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region IComparable Members |
||||
|
||||
int IComparable.CompareTo(object obj) |
||||
{ |
||||
MySqlDateTime otherDate = (MySqlDateTime)obj; |
||||
|
||||
if (Year < otherDate.Year) return -1; |
||||
else if (Year > otherDate.Year) return 1; |
||||
|
||||
if (Month < otherDate.Month) return -1; |
||||
else if (Month > otherDate.Month) return 1; |
||||
|
||||
if (Day < otherDate.Day) return -1; |
||||
else if (Day > otherDate.Day) return 1; |
||||
|
||||
if (Hour < otherDate.Hour) return -1; |
||||
else if (Hour > otherDate.Hour) return 1; |
||||
|
||||
if (Minute < otherDate.Minute) return -1; |
||||
else if (Minute > otherDate.Minute) return 1; |
||||
|
||||
if (Second < otherDate.Second) return -1; |
||||
else if (Second > otherDate.Second) return 1; |
||||
|
||||
if (Millisecond < otherDate.Millisecond) return -1; |
||||
else if (Millisecond > otherDate.Millisecond) return 1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
} |
@ -0,0 +1,173 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Globalization; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
|
||||
public struct MySqlDecimal : IMySqlValue |
||||
{ |
||||
private byte precision; |
||||
private byte scale; |
||||
private string mValue; |
||||
private bool isNull; |
||||
|
||||
internal MySqlDecimal(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = null; |
||||
precision = scale = 0; |
||||
} |
||||
|
||||
internal MySqlDecimal(string val) |
||||
{ |
||||
this.isNull = false; |
||||
precision = scale = 0; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Decimal; } |
||||
} |
||||
|
||||
public byte Precision |
||||
{ |
||||
get { return precision; } |
||||
set { precision = value; } |
||||
} |
||||
|
||||
public byte Scale |
||||
{ |
||||
get { return scale; } |
||||
set { scale = value; } |
||||
} |
||||
|
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Decimal; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return this.Value; } |
||||
} |
||||
|
||||
public decimal Value |
||||
{ |
||||
get { return Convert.ToDecimal(mValue, CultureInfo.InvariantCulture); } |
||||
} |
||||
|
||||
public double ToDouble() |
||||
{ |
||||
return Double.Parse(mValue); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return mValue; |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(decimal); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "DECIMAL"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
decimal v = (val is decimal) ? (decimal)val : Convert.ToDecimal(val); |
||||
string valStr = v.ToString(CultureInfo.InvariantCulture); |
||||
if (binary) |
||||
packet.WriteLenString(valStr); |
||||
else |
||||
packet.WriteStringNoNull(valStr); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlDecimal(true); |
||||
|
||||
string s = String.Empty; |
||||
if (length == -1) |
||||
s = packet.ReadLenString(); |
||||
else |
||||
s = packet.ReadString(length); |
||||
return new MySqlDecimal(s); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
int len = packet.ReadFieldLength(); |
||||
packet.Position += len; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "DECIMAL"; |
||||
row["ProviderDbType"] = MySqlDbType.NewDecimal; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "DECIMAL({0},{1})"; |
||||
row["CreateParameters"] = "precision,scale"; |
||||
row["DataType"] = "System.Decimal"; |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,147 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.Globalization; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
|
||||
internal struct MySqlDouble : IMySqlValue |
||||
{ |
||||
private double mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlDouble(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = 0.0; |
||||
} |
||||
|
||||
public MySqlDouble(double val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Double; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Double; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public double Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(double); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "DOUBLE"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
double v = (val is double) ? (double)val : Convert.ToDouble(val); |
||||
if (binary) |
||||
packet.Write(BitConverter.GetBytes(v)); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString("R", CultureInfo.InvariantCulture)); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, |
||||
bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlDouble(true); |
||||
|
||||
if (length == -1) |
||||
{ |
||||
byte[] b = new byte[8]; |
||||
packet.Read(b, 0, 8); |
||||
return new MySqlDouble(BitConverter.ToDouble(b, 0)); |
||||
} |
||||
return new MySqlDouble(Double.Parse(packet.ReadString(length), |
||||
CultureInfo.InvariantCulture)); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.Position += 8; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "DOUBLE"; |
||||
row["ProviderDbType"] = MySqlDbType.Double; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "DOUBLE"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.Double"; |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,241 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
|
||||
internal struct MySqlGuid : IMySqlValue |
||||
{ |
||||
Guid mValue; |
||||
private bool isNull; |
||||
private byte[] bytes; |
||||
private bool oldGuids; |
||||
|
||||
public MySqlGuid(byte[] buff) |
||||
{ |
||||
oldGuids = false; |
||||
mValue = new Guid(buff); |
||||
isNull = false; |
||||
bytes = buff; |
||||
} |
||||
|
||||
public byte[] Bytes |
||||
{ |
||||
get { return bytes; } |
||||
} |
||||
|
||||
public bool OldGuids |
||||
{ |
||||
get { return oldGuids; } |
||||
set { oldGuids = value; } |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Guid; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Guid; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public Guid Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(Guid); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return OldGuids ? "BINARY(16)" : "CHAR(36)"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
Guid guid = Guid.Empty; |
||||
string valAsString = val as string; |
||||
byte[] valAsByte = val as byte[]; |
||||
|
||||
if (val is Guid) |
||||
guid = (Guid)val; |
||||
else |
||||
{ |
||||
try |
||||
{ |
||||
if (valAsString != null) |
||||
guid = new Guid(valAsString); |
||||
else if (valAsByte != null) |
||||
guid = new Guid(valAsByte); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
throw new MySqlException(Resources.DataNotInSupportedFormat, ex); |
||||
} |
||||
} |
||||
|
||||
if (OldGuids) |
||||
WriteOldGuid(packet, guid, binary); |
||||
else |
||||
{ |
||||
guid.ToString("D"); |
||||
|
||||
if (binary) |
||||
packet.WriteLenString(guid.ToString("D")); |
||||
else |
||||
packet.WriteStringNoNull("'" + MySqlHelper.EscapeString(guid.ToString("D")) + "'"); |
||||
} |
||||
} |
||||
|
||||
private void WriteOldGuid(MySqlPacket packet, Guid guid, bool binary) |
||||
{ |
||||
byte[] bytes = guid.ToByteArray(); |
||||
|
||||
if (binary) |
||||
{ |
||||
packet.WriteLength(bytes.Length); |
||||
packet.Write(bytes); |
||||
} |
||||
else |
||||
{ |
||||
if (packet.Version.isAtLeast(4, 1, 0)) |
||||
packet.WriteStringNoNull("_binary "); |
||||
|
||||
packet.WriteByte((byte)'\''); |
||||
EscapeByteArray(bytes, bytes.Length, packet); |
||||
packet.WriteByte((byte)'\''); |
||||
} |
||||
} |
||||
|
||||
private static void EscapeByteArray(byte[] bytes, int length, MySqlPacket packet) |
||||
{ |
||||
for (int x = 0; x < length; x++) |
||||
{ |
||||
byte b = bytes[x]; |
||||
if (b == '\0') |
||||
{ |
||||
packet.WriteByte((byte)'\\'); |
||||
packet.WriteByte((byte)'0'); |
||||
} |
||||
|
||||
else if (b == '\\' || b == '\'' || b == '\"') |
||||
{ |
||||
packet.WriteByte((byte)'\\'); |
||||
packet.WriteByte(b); |
||||
} |
||||
else |
||||
packet.WriteByte(b); |
||||
} |
||||
} |
||||
|
||||
private MySqlGuid ReadOldGuid(MySqlPacket packet, long length) |
||||
{ |
||||
if (length == -1) |
||||
length = (long)packet.ReadFieldLength(); |
||||
|
||||
byte[] buff = new byte[length]; |
||||
packet.Read(buff, 0, (int)length); |
||||
MySqlGuid g = new MySqlGuid(buff); |
||||
g.OldGuids = OldGuids; |
||||
return g; |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
MySqlGuid g = new MySqlGuid(); |
||||
g.isNull = true; |
||||
g.OldGuids = OldGuids; |
||||
if (!nullVal) |
||||
{ |
||||
if (OldGuids) |
||||
return ReadOldGuid(packet, length); |
||||
string s = String.Empty; |
||||
if (length == -1) |
||||
s = packet.ReadLenString(); |
||||
else |
||||
s = packet.ReadString(length); |
||||
g.mValue = new Guid(s); |
||||
g.isNull = false; |
||||
} |
||||
return g; |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
int len = packet.ReadFieldLength(); |
||||
packet.Position += len; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "GUID"; |
||||
row["ProviderDbType"] = MySqlDbType.Guid; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "BINARY(16)"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.Guid"; |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = false; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,140 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlInt16 : IMySqlValue |
||||
{ |
||||
private short mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlInt16(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = 0; |
||||
} |
||||
|
||||
public MySqlInt16(short val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Int16; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Int16; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public short Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(short); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "SMALLINT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
int v = (val is Int32) ? (int)val : Convert.ToInt32(val); |
||||
if (binary) |
||||
packet.WriteInteger((long)v, 2); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString()); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlInt16(true); |
||||
|
||||
if (length == -1) |
||||
return new MySqlInt16((short)packet.ReadInteger(2)); |
||||
else |
||||
return new MySqlInt16(Int16.Parse(packet.ReadString(length))); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.Position += 2; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "SMALLINT"; |
||||
row["ProviderDbType"] = MySqlDbType.Int16; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "SMALLINT"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.Int16"; |
||||
row["IsAutoincrementable"] = true; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,160 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Globalization; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlInt32 : IMySqlValue |
||||
{ |
||||
private int mValue; |
||||
private bool isNull; |
||||
private bool is24Bit; |
||||
|
||||
private MySqlInt32(MySqlDbType type) |
||||
{ |
||||
is24Bit = type == MySqlDbType.Int24 ? true : false; |
||||
isNull = true; |
||||
mValue = 0; |
||||
} |
||||
|
||||
public MySqlInt32(MySqlDbType type, bool isNull) |
||||
: this(type) |
||||
{ |
||||
this.isNull = isNull; |
||||
} |
||||
|
||||
public MySqlInt32(MySqlDbType type, int val) |
||||
: this(type) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Int32; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Int32; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public int Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(Int32); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return is24Bit ? "MEDIUMINT" : "INT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
int v = (val is Int32) ? (int)val : Convert.ToInt32(val); |
||||
if (binary) |
||||
packet.WriteInteger((long)v, is24Bit ? 3 : 4); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString()); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlInt32((this as IMySqlValue).MySqlDbType, true); |
||||
|
||||
if (length == -1) |
||||
return new MySqlInt32((this as IMySqlValue).MySqlDbType, |
||||
packet.ReadInteger(4)); |
||||
else |
||||
return new MySqlInt32((this as IMySqlValue).MySqlDbType, |
||||
Int32.Parse(packet.ReadString(length), |
||||
CultureInfo.InvariantCulture)); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.Position += 4; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
string[] types = new string[] { "INT", "YEAR", "MEDIUMINT" }; |
||||
MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.Int32, |
||||
MySqlDbType.Year, MySqlDbType.Int24 }; |
||||
|
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
for (int x = 0; x < types.Length; x++) |
||||
{ |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = types[x]; |
||||
row["ProviderDbType"] = dbtype[x]; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = types[x]; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.Int32"; |
||||
row["IsAutoincrementable"] = dbtype[x] == MySqlDbType.Year ? false : true; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,140 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlInt64 : IMySqlValue |
||||
{ |
||||
private long mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlInt64(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = 0; |
||||
} |
||||
|
||||
public MySqlInt64(long val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Int64; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Int64; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public long Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(long); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "BIGINT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
long v = (val is Int64) ? (Int64)val : Convert.ToInt64(val); |
||||
if (binary) |
||||
packet.WriteInteger(v, 8); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString()); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlInt64(true); |
||||
|
||||
if (length == -1) |
||||
return new MySqlInt64((long)packet.ReadULong(8)); |
||||
else |
||||
return new MySqlInt64(Int64.Parse(packet.ReadString(length))); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.Position += 8; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "BIGINT"; |
||||
row["ProviderDbType"] = MySqlDbType.Int64; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "BIGINT"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.Int64"; |
||||
row["IsAutoincrementable"] = true; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,146 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Globalization; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlSingle : IMySqlValue |
||||
{ |
||||
private float mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlSingle(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = 0.0f; |
||||
} |
||||
|
||||
public MySqlSingle(float val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Float; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Single; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public float Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(float); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "FLOAT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
Single v = (val is Single) ? (Single)val : Convert.ToSingle(val); |
||||
if (binary) |
||||
packet.Write(BitConverter.GetBytes(v)); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString("R", |
||||
CultureInfo.InvariantCulture)); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlSingle(true); |
||||
|
||||
if (length == -1) |
||||
{ |
||||
byte[] b = new byte[4]; |
||||
packet.Read(b, 0, 4); |
||||
return new MySqlSingle(BitConverter.ToSingle(b, 0)); |
||||
} |
||||
return new MySqlSingle(Single.Parse(packet.ReadString(length), |
||||
CultureInfo.InvariantCulture)); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.Position += 4; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "FLOAT"; |
||||
row["ProviderDbType"] = MySqlDbType.Float; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "FLOAT"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.Single"; |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,165 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.IO; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlString : IMySqlValue |
||||
{ |
||||
private string mValue; |
||||
private bool isNull; |
||||
private MySqlDbType type; |
||||
|
||||
public MySqlString(MySqlDbType type, bool isNull) |
||||
{ |
||||
this.type = type; |
||||
this.isNull = isNull; |
||||
mValue = String.Empty; |
||||
} |
||||
|
||||
public MySqlString(MySqlDbType type, string val) |
||||
{ |
||||
this.type = type; |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return type; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.String; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public string Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(string); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return type == MySqlDbType.Set ? "SET" : type == MySqlDbType.Enum ? "ENUM" : "VARCHAR"; } |
||||
} |
||||
|
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
string v = val.ToString(); |
||||
if (length > 0) |
||||
{ |
||||
length = Math.Min(length, v.Length); |
||||
v = v.Substring(0, length); |
||||
} |
||||
|
||||
if (binary) |
||||
packet.WriteLenString(v); |
||||
else |
||||
packet.WriteStringNoNull("'" + MySqlHelper.EscapeString(v) + "'"); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlString(type, true); |
||||
|
||||
string s = String.Empty; |
||||
if (length == -1) |
||||
s = packet.ReadLenString(); |
||||
else |
||||
s = packet.ReadString(length); |
||||
MySqlString str = new MySqlString(type, s); |
||||
return str; |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
int len = packet.ReadFieldLength(); |
||||
packet.Position += len; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
string[] types = new string[] { "CHAR", "NCHAR", "VARCHAR", "NVARCHAR", "SET", |
||||
"ENUM", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT" }; |
||||
MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.String, MySqlDbType.String, |
||||
MySqlDbType.VarChar, MySqlDbType.VarChar, MySqlDbType.Set, MySqlDbType.Enum, |
||||
MySqlDbType.TinyText, MySqlDbType.Text, MySqlDbType.MediumText, |
||||
MySqlDbType.LongText }; |
||||
|
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
for (int x = 0; x < types.Length; x++) |
||||
{ |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = types[x]; |
||||
row["ProviderDbType"] = dbtype[x]; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = x < 4 ? types[x] + "({0})" : types[x]; |
||||
row["CreateParameters"] = x < 4 ? "size" : null; |
||||
row["DataType"] = "System.String"; |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = false; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = true; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,206 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlTimeSpan : IMySqlValue |
||||
{ |
||||
private TimeSpan mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlTimeSpan(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = TimeSpan.MinValue; |
||||
} |
||||
|
||||
public MySqlTimeSpan(TimeSpan val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.Time; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Time; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public TimeSpan Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(TimeSpan); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "TIME"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
if (!(val is TimeSpan)) |
||||
throw new MySqlException("Only TimeSpan objects can be serialized by MySqlTimeSpan"); |
||||
|
||||
TimeSpan ts = (TimeSpan)val; |
||||
bool negative = ts.TotalMilliseconds < 0; |
||||
ts = ts.Duration(); |
||||
|
||||
if (binary) |
||||
{ |
||||
packet.WriteByte(8); |
||||
packet.WriteByte((byte)(negative ? 1 : 0)); |
||||
packet.WriteInteger(ts.Days, 4); |
||||
packet.WriteByte((byte)ts.Hours); |
||||
packet.WriteByte((byte)ts.Minutes); |
||||
packet.WriteByte((byte)ts.Seconds); |
||||
} |
||||
else |
||||
{ |
||||
String s = String.Format("'{0}{1} {2:00}:{3:00}:{4:00}.{5}'", |
||||
negative ? "-" : "", ts.Days, ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds); |
||||
|
||||
packet.WriteStringNoNull(s); |
||||
} |
||||
} |
||||
|
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) return new MySqlTimeSpan(true); |
||||
|
||||
if (length >= 0) |
||||
{ |
||||
string value = packet.ReadString(length); |
||||
ParseMySql(value, packet.Version.isAtLeast(4, 1, 0)); |
||||
return this; |
||||
} |
||||
|
||||
long bufLength = packet.ReadByte(); |
||||
int negate = 0; |
||||
if (bufLength > 0) |
||||
negate = packet.ReadByte(); |
||||
|
||||
isNull = false; |
||||
if (bufLength == 0) |
||||
isNull = true; |
||||
else if (bufLength == 5) |
||||
mValue = new TimeSpan(packet.ReadInteger(4), 0, 0, 0); |
||||
else if (bufLength == 8) |
||||
mValue = new TimeSpan(packet.ReadInteger(4), |
||||
packet.ReadByte(), packet.ReadByte(), packet.ReadByte()); |
||||
else |
||||
mValue = new TimeSpan(packet.ReadInteger(4), |
||||
packet.ReadByte(), packet.ReadByte(), packet.ReadByte(), |
||||
packet.ReadInteger(4) / 1000000); |
||||
|
||||
if (negate == 1) |
||||
mValue = mValue.Negate(); |
||||
return this; |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
int len = packet.ReadByte(); |
||||
packet.Position += len; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "TIME"; |
||||
row["ProviderDbType"] = MySqlDbType.Time; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "TIME"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.TimeSpan"; |
||||
row["IsAutoincrementable"] = false; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = false; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return String.Format("{0} {1:00}:{2:00}:{3:00}.{4}", |
||||
mValue.Days, mValue.Hours, mValue.Minutes, mValue.Seconds, mValue.Milliseconds); |
||||
} |
||||
|
||||
private void ParseMySql(string s, bool is41) |
||||
{ |
||||
string[] parts = s.Split(':'); |
||||
int hours = Int32.Parse(parts[0]); |
||||
int mins = Int32.Parse(parts[1]); |
||||
int secs = Int32.Parse(parts[2]); |
||||
if (hours < 0 || parts[0].StartsWith("-")) |
||||
{ |
||||
mins *= -1; |
||||
secs *= -1; |
||||
} |
||||
int days = hours / 24; |
||||
hours = hours - (days * 24); |
||||
mValue = new TimeSpan(days, hours, mins, secs, 0); |
||||
isNull = false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,140 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlUByte : IMySqlValue |
||||
{ |
||||
private byte mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlUByte(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = 0; |
||||
} |
||||
|
||||
public MySqlUByte(byte val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.UByte; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.Byte; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public byte Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(byte); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "TINYINT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
byte v = (val is byte) ? (byte)val : Convert.ToByte(val); |
||||
if (binary) |
||||
packet.WriteByte(v); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString()); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlUByte(true); |
||||
|
||||
if (length == -1) |
||||
return new MySqlUByte((byte)packet.ReadByte()); |
||||
else |
||||
return new MySqlUByte(Byte.Parse(packet.ReadString(length))); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.ReadByte(); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "TINY INT"; |
||||
row["ProviderDbType"] = MySqlDbType.UByte; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "TINYINT UNSIGNED"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.Byte"; |
||||
row["IsAutoincrementable"] = true; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = true; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,140 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlUInt16 : IMySqlValue |
||||
{ |
||||
private ushort mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlUInt16(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = 0; |
||||
} |
||||
|
||||
public MySqlUInt16(ushort val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.UInt16; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.UInt16; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public ushort Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(ushort); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "SMALLINT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
int v = (val is UInt16) ? (UInt16)val : Convert.ToUInt16(val); |
||||
if (binary) |
||||
packet.WriteInteger((long)v, 2); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString()); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlUInt16(true); |
||||
|
||||
if (length == -1) |
||||
return new MySqlUInt16((ushort)packet.ReadInteger(2)); |
||||
else |
||||
return new MySqlUInt16(UInt16.Parse(packet.ReadString(length))); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.Position += 2; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "SMALLINT"; |
||||
row["ProviderDbType"] = MySqlDbType.UInt16; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "SMALLINT UNSIGNED"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.UInt16"; |
||||
row["IsAutoincrementable"] = true; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = true; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,159 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Globalization; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlUInt32 : IMySqlValue |
||||
{ |
||||
private uint mValue; |
||||
private bool isNull; |
||||
private bool is24Bit; |
||||
|
||||
private MySqlUInt32(MySqlDbType type) |
||||
{ |
||||
is24Bit = type == MySqlDbType.Int24 ? true : false; |
||||
isNull = true; |
||||
mValue = 0; |
||||
} |
||||
|
||||
public MySqlUInt32(MySqlDbType type, bool isNull) |
||||
: this(type) |
||||
{ |
||||
this.isNull = isNull; |
||||
} |
||||
|
||||
public MySqlUInt32(MySqlDbType type, uint val) |
||||
: this(type) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.UInt32; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.UInt32; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public uint Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(UInt32); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return is24Bit ? "MEDIUMINT" : "INT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object v, int length) |
||||
{ |
||||
uint val = (v is uint) ? (uint)v : Convert.ToUInt32(v); |
||||
if (binary) |
||||
packet.WriteInteger((long)val, is24Bit ? 3 : 4); |
||||
else |
||||
packet.WriteStringNoNull(val.ToString()); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlUInt32((this as IMySqlValue).MySqlDbType, true); |
||||
|
||||
if (length == -1) |
||||
return new MySqlUInt32((this as IMySqlValue).MySqlDbType, |
||||
(uint)packet.ReadInteger(4)); |
||||
else |
||||
return new MySqlUInt32((this as IMySqlValue).MySqlDbType, |
||||
UInt32.Parse(packet.ReadString(length), NumberStyles.Any, CultureInfo.InvariantCulture)); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.Position += 4; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
string[] types = new string[] { "MEDIUMINT", "INT" }; |
||||
MySqlDbType[] dbtype = new MySqlDbType[] { MySqlDbType.UInt24, |
||||
MySqlDbType.UInt32 }; |
||||
|
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
for (int x = 0; x < types.Length; x++) |
||||
{ |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = types[x]; |
||||
row["ProviderDbType"] = dbtype[x]; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = types[x] + " UNSIGNED"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.UInt32"; |
||||
row["IsAutoincrementable"] = true; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = true; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,140 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal struct MySqlUInt64 : IMySqlValue |
||||
{ |
||||
private ulong mValue; |
||||
private bool isNull; |
||||
|
||||
public MySqlUInt64(bool isNull) |
||||
{ |
||||
this.isNull = isNull; |
||||
mValue = 0; |
||||
} |
||||
|
||||
public MySqlUInt64(ulong val) |
||||
{ |
||||
this.isNull = false; |
||||
mValue = val; |
||||
} |
||||
|
||||
#region IMySqlValue Members |
||||
|
||||
public bool IsNull |
||||
{ |
||||
get { return isNull; } |
||||
} |
||||
|
||||
MySqlDbType IMySqlValue.MySqlDbType |
||||
{ |
||||
get { return MySqlDbType.UInt64; } |
||||
} |
||||
|
||||
DbType IMySqlValue.DbType |
||||
{ |
||||
get { return DbType.UInt64; } |
||||
} |
||||
|
||||
object IMySqlValue.Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
public ulong Value |
||||
{ |
||||
get { return mValue; } |
||||
} |
||||
|
||||
Type IMySqlValue.SystemType |
||||
{ |
||||
get { return typeof(ulong); } |
||||
} |
||||
|
||||
string IMySqlValue.MySqlTypeName |
||||
{ |
||||
get { return "BIGINT"; } |
||||
} |
||||
|
||||
void IMySqlValue.WriteValue(MySqlPacket packet, bool binary, object val, int length) |
||||
{ |
||||
ulong v = (val is ulong) ? (ulong)val : Convert.ToUInt64(val); |
||||
if (binary) |
||||
packet.WriteInteger((long)v, 8); |
||||
else |
||||
packet.WriteStringNoNull(v.ToString()); |
||||
} |
||||
|
||||
IMySqlValue IMySqlValue.ReadValue(MySqlPacket packet, long length, bool nullVal) |
||||
{ |
||||
if (nullVal) |
||||
return new MySqlUInt64(true); |
||||
|
||||
if (length == -1) |
||||
return new MySqlUInt64(packet.ReadULong(8)); |
||||
else |
||||
return new MySqlUInt64(UInt64.Parse(packet.ReadString(length))); |
||||
} |
||||
|
||||
void IMySqlValue.SkipValue(MySqlPacket packet) |
||||
{ |
||||
packet.Position += 8; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
internal static void SetDSInfo(DataTable dsTable) |
||||
{ |
||||
// we use name indexing because this method will only be called |
||||
// when GetSchema is called for the DataSourceInformation |
||||
// collection and then it wil be cached. |
||||
DataRow row = dsTable.NewRow(); |
||||
row["TypeName"] = "BIGINT"; |
||||
row["ProviderDbType"] = MySqlDbType.UInt64; |
||||
row["ColumnSize"] = 0; |
||||
row["CreateFormat"] = "BIGINT UNSIGNED"; |
||||
row["CreateParameters"] = null; |
||||
row["DataType"] = "System.UInt64"; |
||||
row["IsAutoincrementable"] = true; |
||||
row["IsBestMatch"] = true; |
||||
row["IsCaseSensitive"] = false; |
||||
row["IsFixedLength"] = true; |
||||
row["IsFixedPrecisionScale"] = true; |
||||
row["IsLong"] = false; |
||||
row["IsNullable"] = true; |
||||
row["IsSearchable"] = true; |
||||
row["IsSearchableWithLike"] = false; |
||||
row["IsUnsigned"] = true; |
||||
row["MaximumScale"] = 0; |
||||
row["MinimumScale"] = 0; |
||||
row["IsConcurrencyType"] = DBNull.Value; |
||||
row["IsLiteralSupported"] = false; |
||||
row["LiteralPrefix"] = null; |
||||
row["LiteralSuffix"] = null; |
||||
row["NativeDataType"] = null; |
||||
dsTable.Rows.Add(row); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,41 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.Globalization; |
||||
using MySql.Data.MySqlClient; |
||||
|
||||
namespace MySql.Data.Types |
||||
{ |
||||
internal interface IMySqlValue |
||||
{ |
||||
bool IsNull { get; } |
||||
MySqlDbType MySqlDbType { get; } |
||||
DbType DbType { get; } |
||||
object Value { get; /*set;*/ } |
||||
Type SystemType { get; } |
||||
string MySqlTypeName { get; } |
||||
|
||||
void WriteValue(MySqlPacket packet, bool binary, object value, int length); |
||||
IMySqlValue ReadValue(MySqlPacket packet, long length, bool isNull); |
||||
void SkipValue(MySqlPacket packet); |
||||
} |
||||
} |
@ -0,0 +1,339 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.ComponentModel; |
||||
using System.Text; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
public class DbConnectionStringBuilder : IDictionary, ICollection, IEnumerable, ICustomTypeDescriptor |
||||
{ |
||||
private string connectionString; |
||||
private Hashtable hash; |
||||
private bool browsable; |
||||
|
||||
public DbConnectionStringBuilder() |
||||
{ |
||||
hash = new Hashtable(StringComparer.InvariantCultureIgnoreCase); |
||||
browsable = false; |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public bool BrowsableConnectionString |
||||
{ |
||||
get { return browsable; } |
||||
set { browsable = value; } |
||||
} |
||||
|
||||
public string ConnectionString |
||||
{ |
||||
get { return connectionString; } |
||||
set |
||||
{ |
||||
Clear(); |
||||
ParseConnectionString(value); |
||||
connectionString = value; |
||||
} |
||||
} |
||||
|
||||
public virtual object this[string key] |
||||
{ |
||||
get { return hash[key]; } |
||||
set { Add(key, value); } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region IDictionary Members |
||||
|
||||
public void Add(object key, object value) |
||||
{ |
||||
hash[key] = value; |
||||
//TODO: update connection string |
||||
} |
||||
|
||||
public virtual void Clear() |
||||
{ |
||||
connectionString = null; |
||||
hash.Clear(); |
||||
} |
||||
|
||||
public bool Contains(object key) |
||||
{ |
||||
return hash.ContainsKey(key); |
||||
} |
||||
|
||||
public IDictionaryEnumerator GetEnumerator() |
||||
{ |
||||
return hash.GetEnumerator(); |
||||
} |
||||
|
||||
public bool IsFixedSize |
||||
{ |
||||
get { return false; } |
||||
} |
||||
|
||||
public bool IsReadOnly |
||||
{ |
||||
get { return false; } |
||||
} |
||||
|
||||
public ICollection Keys |
||||
{ |
||||
get { return hash.Keys; } |
||||
} |
||||
|
||||
public void Remove(object key) |
||||
{ |
||||
hash.Remove(key); |
||||
//TODO: update connection string |
||||
} |
||||
|
||||
public ICollection Values |
||||
{ |
||||
get { return hash.Values; } |
||||
} |
||||
|
||||
public object this[object key] |
||||
{ |
||||
get |
||||
{ |
||||
return this[(string)key]; |
||||
} |
||||
set |
||||
{ |
||||
this[(string)key] = value; |
||||
} |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region ICollection Members |
||||
|
||||
public void CopyTo(Array array, int index) |
||||
{ |
||||
hash.CopyTo(array, index); |
||||
} |
||||
|
||||
public int Count |
||||
{ |
||||
get { return hash.Count; } |
||||
} |
||||
|
||||
public bool IsSynchronized |
||||
{ |
||||
get { return hash.IsSynchronized; } |
||||
} |
||||
|
||||
public object SyncRoot |
||||
{ |
||||
get { return hash.SyncRoot; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region IEnumerable Members |
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() |
||||
{ |
||||
return hash.GetEnumerator(); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region ICustomTypeDescriptor Members |
||||
|
||||
public AttributeCollection GetAttributes() |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public string GetClassName() |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public string GetComponentName() |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public TypeConverter GetConverter() |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public EventDescriptor GetDefaultEvent() |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public PropertyDescriptor GetDefaultProperty() |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public object GetEditor(Type editorBaseType) |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public EventDescriptorCollection GetEvents(Attribute[] attributes) |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public EventDescriptorCollection GetEvents() |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public PropertyDescriptorCollection GetProperties(Attribute[] attributes) |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public PropertyDescriptorCollection GetProperties() |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public object GetPropertyOwner(PropertyDescriptor pd) |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public virtual object TryGetValue(string keyword, out object value) |
||||
{ |
||||
if (!hash.ContainsKey(keyword)) |
||||
{ |
||||
value = null; |
||||
return false; |
||||
} |
||||
value = hash[keyword]; |
||||
return true; |
||||
} |
||||
|
||||
private void ParseConnectionString(string connectString) |
||||
{ |
||||
if (connectString == null) return; |
||||
|
||||
StringBuilder key = new StringBuilder(); |
||||
StringBuilder value = new StringBuilder(); |
||||
bool keyDone = false; |
||||
|
||||
foreach (char c in connectString) |
||||
{ |
||||
if (c == '=') |
||||
keyDone = true; |
||||
else if (c == ';') |
||||
{ |
||||
string keyStr = key.ToString().Trim(); |
||||
string valueStr = value.ToString().Trim(); |
||||
valueStr = CleanValue(valueStr); |
||||
if (keyStr.Length > 0) |
||||
this[keyStr] = valueStr; |
||||
keyDone = false; |
||||
key.Remove(0, key.Length); |
||||
value.Remove(0, value.Length); |
||||
} |
||||
else if (keyDone) |
||||
value.Append(c); |
||||
else |
||||
key.Append(c); |
||||
} |
||||
|
||||
if (key.Length == 0) return; |
||||
this[key.ToString().Trim()] = CleanValue(value.ToString().Trim()); |
||||
} |
||||
|
||||
private string CleanValue(string value) |
||||
{ |
||||
if ((value.StartsWith("'") && value.EndsWith("'")) || |
||||
(value.StartsWith("\"") && value.EndsWith("\""))) |
||||
{ |
||||
value = value.Substring(1); |
||||
value = value.Substring(0, value.Length - 1); |
||||
} |
||||
return value; |
||||
} |
||||
|
||||
/* private void ParseConnectionString(string value) |
||||
{ |
||||
String[] keyvalues = src.Split(';'); |
||||
String[] newkeyvalues = new String[keyvalues.Length]; |
||||
int x = 0; |
||||
|
||||
// first run through the array and check for any keys that |
||||
// have ; in their value |
||||
foreach (String keyvalue in keyvalues) |
||||
{ |
||||
// check for trailing ; at the end of the connection string |
||||
if (keyvalue.Length == 0) continue; |
||||
|
||||
// this value has an '=' sign so we are ok |
||||
if (keyvalue.IndexOf('=') >= 0) |
||||
{ |
||||
newkeyvalues[x++] = keyvalue; |
||||
} |
||||
else |
||||
{ |
||||
newkeyvalues[x - 1] += ";"; |
||||
newkeyvalues[x - 1] += keyvalue; |
||||
} |
||||
} |
||||
|
||||
Hashtable hash = new Hashtable(); |
||||
|
||||
// now we run through our normalized key-values, splitting on equals |
||||
for (int y = 0; y < x; y++) |
||||
{ |
||||
String[] parts = newkeyvalues[y].Split('='); |
||||
|
||||
// first trim off any space and lowercase the key |
||||
parts[0] = parts[0].Trim().ToLower(); |
||||
parts[1] = parts[1].Trim(); |
||||
|
||||
// we also want to clear off any quotes |
||||
if (parts[1].Length >= 2) |
||||
{ |
||||
if ((parts[1][0] == '"' && parts[1][parts[1].Length - 1] == '"') || |
||||
(parts[1][0] == '\'' && parts[1][parts[1].Length - 1] == '\'')) |
||||
{ |
||||
parts[1] = parts[1].Substring(1, parts[1].Length - 2); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
parts[1] = parts[1]; |
||||
} |
||||
parts[0] = parts[0].Trim('\'', '"'); |
||||
|
||||
hash[parts[0]] = parts[1]; |
||||
} |
||||
return hash; |
||||
}*/ |
||||
} |
||||
} |
@ -0,0 +1,60 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
public abstract class DbException : ExternalException |
||||
{ |
||||
private int errorCode; |
||||
|
||||
public DbException() |
||||
: base() |
||||
{ |
||||
} |
||||
|
||||
public DbException(string message) : base(message) |
||||
{ |
||||
} |
||||
|
||||
public DbException(string message, Exception innerException) |
||||
: base(message, innerException) |
||||
{ |
||||
} |
||||
|
||||
public DbException(string message, int errorCode) |
||||
: base(message) |
||||
{ |
||||
this.errorCode = errorCode; |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
// public int ErrorCode |
||||
// { |
||||
// get { return errorCode; } |
||||
// } |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
} |
@ -0,0 +1,197 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.IO; |
||||
using MySql.Data.MySqlClient; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
internal class BufferedStream : Stream |
||||
{ |
||||
private byte[] writeBuffer; |
||||
private byte[] readBuffer; |
||||
private int writePos; |
||||
private int readLength; |
||||
private int readPos; |
||||
private int bufferSize; |
||||
private Stream baseStream; |
||||
|
||||
public BufferedStream(Stream stream) |
||||
{ |
||||
baseStream = stream; |
||||
bufferSize = 4096; |
||||
readBuffer = new byte[bufferSize]; |
||||
writeBuffer = new byte[bufferSize]; |
||||
} |
||||
|
||||
#region Stream Implementation |
||||
|
||||
public override bool CanRead |
||||
{ |
||||
get |
||||
{ |
||||
if (baseStream != null) return baseStream.CanRead; |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public override bool CanSeek |
||||
{ |
||||
get |
||||
{ |
||||
if (baseStream != null) return baseStream.CanSeek; |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public override bool CanWrite |
||||
{ |
||||
get |
||||
{ |
||||
if (baseStream != null) return baseStream.CanWrite; |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public override void Flush() |
||||
{ |
||||
if (baseStream == null) |
||||
throw new InvalidOperationException(Resources.ObjectDisposed); |
||||
if (writePos == 0) return; |
||||
|
||||
baseStream.Write(writeBuffer, 0, writePos); |
||||
baseStream.Flush(); |
||||
writePos = 0; |
||||
} |
||||
|
||||
public override long Length |
||||
{ |
||||
get |
||||
{ |
||||
if (baseStream == null) |
||||
throw new InvalidOperationException(Resources.ObjectDisposed); |
||||
Flush(); |
||||
return baseStream.Length; |
||||
} |
||||
|
||||
} |
||||
|
||||
public override long Position |
||||
{ |
||||
get |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
set |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
} |
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) |
||||
{ |
||||
if (buffer == null) |
||||
throw new ArgumentNullException("buffer", Resources.ParameterCannotBeNull); |
||||
if (offset < 0) |
||||
throw new ArgumentOutOfRangeException("offset", Resources.OffsetCannotBeNegative); |
||||
if (count < 0) |
||||
throw new ArgumentOutOfRangeException("count", Resources.CountCannotBeNegative); |
||||
if ((buffer.Length - offset) < count) |
||||
throw new ArgumentException(Resources.OffsetMustBeValid); |
||||
if (baseStream == null) |
||||
throw new InvalidOperationException(Resources.ObjectDisposed); |
||||
|
||||
if ((readLength - readPos) == 0) |
||||
{ |
||||
TryToFillReadBuffer(); |
||||
if (readLength == 0) return 0; |
||||
} |
||||
|
||||
int inBuffer = readLength - readPos; |
||||
int toRead = count; |
||||
if (toRead > inBuffer) |
||||
toRead = inBuffer; |
||||
Buffer.BlockCopy(readBuffer, readPos, buffer, offset, toRead); |
||||
readPos += toRead; |
||||
count -= toRead; |
||||
if (count > 0) |
||||
{ |
||||
int read = baseStream.Read(buffer, offset + toRead, count); |
||||
toRead += read; |
||||
readPos = readLength = 0; |
||||
} |
||||
return toRead; |
||||
} |
||||
|
||||
private void TryToFillReadBuffer() |
||||
{ |
||||
int read = baseStream.Read(readBuffer, 0, bufferSize); |
||||
readPos = 0; |
||||
readLength = read; |
||||
} |
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public override void SetLength(long value) |
||||
{ |
||||
throw new Exception("The method or operation is not implemented."); |
||||
} |
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) |
||||
{ |
||||
if (buffer == null) |
||||
throw new ArgumentNullException("buffer", Resources.ParameterCannotBeNull); |
||||
if (offset < 0) |
||||
throw new ArgumentOutOfRangeException("offset", Resources.OffsetCannotBeNegative); |
||||
if (count < 0) |
||||
throw new ArgumentOutOfRangeException("count", Resources.CountCannotBeNegative); |
||||
if ((buffer.Length - offset) < count) |
||||
throw new ArgumentException(Resources.OffsetMustBeValid); |
||||
if (baseStream == null) |
||||
throw new InvalidOperationException(Resources.ObjectDisposed); |
||||
|
||||
// if we don't have enough room in our current write buffer for the data |
||||
// then flush the data |
||||
int roomLeft = bufferSize - writePos; |
||||
if (count > roomLeft) |
||||
Flush(); |
||||
|
||||
// if the data will not fit into a entire buffer, then there is no need to buffer it. |
||||
// We just send it down |
||||
if (count > bufferSize) |
||||
baseStream.Write(buffer, offset, count); |
||||
else |
||||
{ |
||||
// if we get here then there is room in our buffer for the data. We store it and |
||||
// adjust our internal lengths. |
||||
Buffer.BlockCopy(buffer, offset, writeBuffer, writePos, count); |
||||
writePos += count; |
||||
} |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for Win32. |
||||
/// </summary> |
||||
internal class WinCE |
||||
{ |
||||
[DllImport("coredll", SetLastError=true)] |
||||
internal static extern Int32 WaitForSingleObject(IntPtr handle, Int32 milliseconds); |
||||
} |
||||
} |
@ -0,0 +1,917 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.Data.Common; |
||||
using System.IO; |
||||
using System.Collections; |
||||
using System.Text; |
||||
using MySql.Data.Common; |
||||
using System.ComponentModel; |
||||
using System.Threading; |
||||
using System.Diagnostics; |
||||
using System.Globalization; |
||||
using System.Collections.Generic; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
#if !CF |
||||
using System.Transactions; |
||||
#endif |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ClassSummary/*'/> |
||||
#if !CF |
||||
[System.Drawing.ToolboxBitmap(typeof(MySqlCommand), "MySqlClient.resources.command.bmp")] |
||||
[System.ComponentModel.DesignerCategory("Code")] |
||||
#endif |
||||
public sealed class MySqlCommand : DbCommand, ICloneable |
||||
{ |
||||
MySqlConnection connection; |
||||
MySqlTransaction curTransaction; |
||||
string cmdText; |
||||
CommandType cmdType; |
||||
long updatedRowCount; |
||||
UpdateRowSource updatedRowSource; |
||||
MySqlParameterCollection parameters; |
||||
private IAsyncResult asyncResult; |
||||
private bool designTimeVisible; |
||||
internal Int64 lastInsertedId; |
||||
private PreparableStatement statement; |
||||
private int commandTimeout; |
||||
private bool resetSqlSelect; |
||||
List<MySqlCommand> batch; |
||||
private string batchableCommandText; |
||||
CommandTimer commandTimer; |
||||
|
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ctor1/*'/> |
||||
public MySqlCommand() |
||||
{ |
||||
designTimeVisible = true; |
||||
cmdType = CommandType.Text; |
||||
parameters = new MySqlParameterCollection(this); |
||||
updatedRowSource = UpdateRowSource.Both; |
||||
cmdText = String.Empty; |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ctor2/*'/> |
||||
public MySqlCommand(string cmdText) |
||||
: this() |
||||
{ |
||||
CommandText = cmdText; |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ctor3/*'/> |
||||
public MySqlCommand(string cmdText, MySqlConnection connection) |
||||
: this(cmdText) |
||||
{ |
||||
Connection = connection; |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ctor4/*'/> |
||||
public MySqlCommand(string cmdText, MySqlConnection connection, |
||||
MySqlTransaction transaction) |
||||
: |
||||
this(cmdText, connection) |
||||
{ |
||||
curTransaction = transaction; |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/LastInseredId/*'/> |
||||
#if !CF |
||||
[Browsable(false)] |
||||
#endif |
||||
public Int64 LastInsertedId |
||||
{ |
||||
get { return lastInsertedId; } |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/CommandText/*'/> |
||||
#if !CF |
||||
[Category("Data")] |
||||
[Description("Command text to execute")] |
||||
[Editor("MySql.Data.Common.Design.SqlCommandTextEditor,MySqlClient.Design", typeof(System.Drawing.Design.UITypeEditor))] |
||||
#endif |
||||
public override string CommandText |
||||
{ |
||||
get { return cmdText; } |
||||
set |
||||
{ |
||||
cmdText = value; |
||||
statement = null; |
||||
batchableCommandText = null; |
||||
if (cmdText != null && cmdText.EndsWith("DEFAULT VALUES")) |
||||
{ |
||||
cmdText = cmdText.Substring(0, cmdText.Length - 14); |
||||
cmdText = cmdText + "() VALUES ()"; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/CommandTimeout/*'/> |
||||
#if !CF |
||||
[Category("Misc")] |
||||
[Description("Time to wait for command to execute")] |
||||
[DefaultValue(30)] |
||||
#endif |
||||
public override int CommandTimeout |
||||
{ |
||||
get { return commandTimeout == 0 ? 30 : commandTimeout; } |
||||
set |
||||
{ |
||||
if (commandTimeout < 0) |
||||
throw new ArgumentException("Command timeout must not be negative"); |
||||
|
||||
// Timeout in milliseconds should not exceed maximum for 32 bit |
||||
// signed integer (~24 days), because underlying driver (and streams) |
||||
// use milliseconds expressed ints for timeout values. |
||||
// Hence, truncate the value. |
||||
int timeout = Math.Min(value, Int32.MaxValue / 1000); |
||||
if (timeout != value) |
||||
{ |
||||
MySqlTrace.LogWarning(connection.ServerThread, |
||||
"Command timeout value too large (" |
||||
+ value + " seconds). Changed to max. possible value (" |
||||
+ timeout + " seconds)"); |
||||
} |
||||
commandTimeout = timeout; |
||||
} |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/CommandType/*'/> |
||||
#if !CF |
||||
[Category("Data")] |
||||
#endif |
||||
public override CommandType CommandType |
||||
{ |
||||
get { return cmdType; } |
||||
set { cmdType = value; } |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/IsPrepared/*'/> |
||||
#if !CF |
||||
[Browsable(false)] |
||||
#endif |
||||
public bool IsPrepared |
||||
{ |
||||
get { return statement != null && statement.IsPrepared; } |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/Connection/*'/> |
||||
#if !CF |
||||
[Category("Behavior")] |
||||
[Description("Connection used by the command")] |
||||
#endif |
||||
public new MySqlConnection Connection |
||||
{ |
||||
get { return connection; } |
||||
set |
||||
{ |
||||
/* |
||||
* The connection is associated with the transaction |
||||
* so set the transaction object to return a null reference if the connection |
||||
* is reset. |
||||
*/ |
||||
if (connection != value) |
||||
Transaction = null; |
||||
|
||||
connection = value; |
||||
|
||||
// if the user has not already set the command timeout, then |
||||
// take the default from the connection |
||||
if (connection != null && commandTimeout == 0) |
||||
commandTimeout = (int)connection.Settings.DefaultCommandTimeout; |
||||
} |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/Parameters/*'/> |
||||
#if !CF |
||||
[Category("Data")] |
||||
[Description("The parameters collection")] |
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] |
||||
#endif |
||||
public new MySqlParameterCollection Parameters |
||||
{ |
||||
get { return parameters; } |
||||
} |
||||
|
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/Transaction/*'/> |
||||
#if !CF |
||||
[Browsable(false)] |
||||
#endif |
||||
public new MySqlTransaction Transaction |
||||
{ |
||||
get { return curTransaction; } |
||||
set { curTransaction = value; } |
||||
} |
||||
|
||||
/* /// <include file='docs/mysqlcommand.xml' path='docs/UpdatedRowSource/*'/> |
||||
#if !CF |
||||
[Category("Behavior")] |
||||
#endif |
||||
public override UpdateRowSource UpdatedRowSource |
||||
{ |
||||
get { return updatedRowSource; } |
||||
set { updatedRowSource = value; } |
||||
}*/ |
||||
|
||||
internal List<MySqlCommand> Batch |
||||
{ |
||||
get { return batch; } |
||||
} |
||||
|
||||
internal string BatchableCommandText |
||||
{ |
||||
get { return batchableCommandText; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Methods |
||||
|
||||
/// <summary> |
||||
/// Attempts to cancel the execution of a currently active command |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// Cancelling a currently active query only works with MySQL versions 5.0.0 and higher. |
||||
/// </remarks> |
||||
public override void Cancel() |
||||
{ |
||||
connection.CancelQuery(connection.ConnectionTimeout); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Creates a new instance of a <see cref="MySqlParameter"/> object. |
||||
/// </summary> |
||||
/// <remarks> |
||||
/// This method is a strongly-typed version of <see cref="IDbCommand.CreateParameter"/>. |
||||
/// </remarks> |
||||
/// <returns>A <see cref="MySqlParameter"/> object.</returns> |
||||
/// |
||||
public new MySqlParameter CreateParameter() |
||||
{ |
||||
return (MySqlParameter)CreateDbParameter(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Check the connection to make sure |
||||
/// - it is open |
||||
/// - it is not currently being used by a reader |
||||
/// - and we have the right version of MySQL for the requested command type |
||||
/// </summary> |
||||
private void CheckState() |
||||
{ |
||||
// There must be a valid and open connection. |
||||
if (connection == null) |
||||
throw new InvalidOperationException("Connection must be valid and open."); |
||||
|
||||
if (connection.State != ConnectionState.Open && !connection.SoftClosed) |
||||
throw new InvalidOperationException("Connection must be valid and open."); |
||||
|
||||
// Data readers have to be closed first |
||||
if (connection.Reader != null) |
||||
throw new MySqlException("There is already an open DataReader associated with this Connection which must be closed first."); |
||||
|
||||
if (CommandType == CommandType.StoredProcedure && !connection.driver.Version.isAtLeast(5, 0, 0)) |
||||
throw new MySqlException("Stored procedures are not supported on this version of MySQL"); |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ExecuteNonQuery/*'/> |
||||
public override int ExecuteNonQuery() |
||||
{ |
||||
MySqlDataReader reader = null; |
||||
using (reader = ExecuteReader()) |
||||
{ |
||||
} |
||||
|
||||
return reader.RecordsAffected; |
||||
} |
||||
|
||||
internal void ClearCommandTimer() |
||||
{ |
||||
if (commandTimer != null) |
||||
{ |
||||
commandTimer.Dispose(); |
||||
commandTimer = null; |
||||
} |
||||
} |
||||
|
||||
internal void Close(MySqlDataReader reader) |
||||
{ |
||||
if (statement != null) |
||||
statement.Close(reader); |
||||
ResetSqlSelectLimit(); |
||||
connection.driver.CloseQuery(connection, statement.StatementId); |
||||
ClearCommandTimer(); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Reset SQL_SELECT_LIMIT that could have been modified by CommandBehavior. |
||||
/// </summary> |
||||
internal void ResetSqlSelectLimit() |
||||
{ |
||||
// if we are supposed to reset the sql select limit, do that here |
||||
if (resetSqlSelect) |
||||
{ |
||||
resetSqlSelect = false; |
||||
new MySqlCommand("SET SQL_SELECT_LIMIT=-1", connection).ExecuteNonQuery(); |
||||
} |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ExecuteReader/*'/> |
||||
public new MySqlDataReader ExecuteReader() |
||||
{ |
||||
return ExecuteReader(CommandBehavior.Default); |
||||
} |
||||
|
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ExecuteReader1/*'/> |
||||
public new MySqlDataReader ExecuteReader (CommandBehavior behavior) |
||||
{ |
||||
|
||||
CheckState(); |
||||
Driver driver = connection.driver; |
||||
lock (driver) |
||||
{ |
||||
|
||||
// We have to recheck that there is no reader, after we got the lock |
||||
if (connection.Reader != null) |
||||
{ |
||||
throw new MySqlException(Resources.DataReaderOpen); |
||||
} |
||||
#if !CF |
||||
System.Transactions.Transaction curTrans = System.Transactions.Transaction.Current; |
||||
|
||||
if (curTrans != null) |
||||
{ |
||||
TransactionStatus status = TransactionStatus.InDoubt; |
||||
try |
||||
{ |
||||
// in some cases (during state transitions) this throws |
||||
// an exception. Ignore exceptions, we're only interested |
||||
// whether transaction was aborted or not. |
||||
status = curTrans.TransactionInformation.Status; |
||||
} |
||||
catch(TransactionException) |
||||
{ |
||||
} |
||||
if (status == TransactionStatus.Aborted) |
||||
throw new TransactionAbortedException(); |
||||
} |
||||
#endif |
||||
commandTimer = new CommandTimer(connection, CommandTimeout); |
||||
|
||||
lastInsertedId = -1; |
||||
if (cmdText == null || |
||||
cmdText.Trim().Length == 0) |
||||
throw new InvalidOperationException(Resources.CommandTextNotInitialized); |
||||
|
||||
string sql = TrimSemicolons(cmdText); |
||||
|
||||
if (CommandType == CommandType.TableDirect) |
||||
sql = "SELECT * FROM " + sql; |
||||
|
||||
// now we check to see if we are executing a query that is buggy |
||||
// in 4.1 |
||||
connection.driver.IsExecutingBuggyQuery = false; |
||||
if (!connection.driver.Version.isAtLeast(5, 0, 0) && |
||||
connection.driver.Version.isAtLeast(4, 1, 0)) |
||||
{ |
||||
string snippet = sql; |
||||
if (snippet.Length > 17) |
||||
snippet = sql.Substring(0, 17); |
||||
snippet = snippet.ToUpper(CultureInfo.InvariantCulture); |
||||
connection.driver.IsExecutingBuggyQuery = |
||||
snippet.StartsWith("DESCRIBE") || |
||||
snippet.StartsWith("SHOW TABLE STATUS"); |
||||
} |
||||
|
||||
if (statement == null || !statement.IsPrepared) |
||||
{ |
||||
if (CommandType == CommandType.StoredProcedure) |
||||
statement = new StoredProcedure(this, sql); |
||||
else |
||||
statement = new PreparableStatement(this, sql); |
||||
} |
||||
|
||||
// stored procs are the only statement type that need do anything during resolve |
||||
statement.Resolve(false); |
||||
|
||||
// Now that we have completed our resolve step, we can handle our |
||||
// command behaviors |
||||
HandleCommandBehaviors(behavior); |
||||
|
||||
updatedRowCount = -1; |
||||
try |
||||
{ |
||||
MySqlDataReader reader = new MySqlDataReader(this, statement, behavior); |
||||
connection.Reader = reader; |
||||
// execute the statement |
||||
statement.Execute(); |
||||
// wait for data to return |
||||
reader.NextResult(); |
||||
return reader; |
||||
} |
||||
catch (TimeoutException tex) |
||||
{ |
||||
connection.HandleTimeout(tex); |
||||
return null; |
||||
} |
||||
catch (MySqlException ex) |
||||
{ |
||||
connection.Reader = null; |
||||
if (ex.InnerException is TimeoutException) |
||||
throw ex; // already handled |
||||
|
||||
try |
||||
{ |
||||
ResetSqlSelectLimit(); |
||||
} |
||||
catch (Exception ex2) |
||||
{ |
||||
// Reset SqlLimit did not work, connection is hosed. |
||||
Connection.Abort(); |
||||
throw new MySqlException(ex.Message, true, ex); |
||||
} |
||||
|
||||
// if we caught an exception because of a cancel, then just return null |
||||
if (ex.Number == 1317) |
||||
return null; |
||||
|
||||
if (ex.IsFatal) |
||||
Connection.Close(); |
||||
if (ex.Number == 0) |
||||
throw new MySqlException(Resources.FatalErrorDuringExecute, ex); |
||||
throw; |
||||
} |
||||
finally |
||||
{ |
||||
if (connection != null && connection.Reader == null) |
||||
{ |
||||
// Comething want seriously wrong, and reader would not be |
||||
// able to clear timeout on closing. |
||||
// So we clear timeout here. |
||||
ClearCommandTimer(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/ExecuteScalar/*'/> |
||||
public override object ExecuteScalar() |
||||
{ |
||||
lastInsertedId = -1; |
||||
object val = null; |
||||
|
||||
using (MySqlDataReader reader = ExecuteReader()) |
||||
{ |
||||
if (reader == null) return null; |
||||
|
||||
if (reader.Read()) |
||||
val = reader.GetValue(0); |
||||
} |
||||
|
||||
return val; |
||||
} |
||||
|
||||
private void HandleCommandBehaviors(CommandBehavior behavior) |
||||
{ |
||||
if ((behavior & CommandBehavior.SchemaOnly) != 0) |
||||
{ |
||||
new MySqlCommand("SET SQL_SELECT_LIMIT=0", connection).ExecuteNonQuery(); |
||||
resetSqlSelect = true; |
||||
} |
||||
else if ((behavior & CommandBehavior.SingleRow) != 0) |
||||
{ |
||||
new MySqlCommand("SET SQL_SELECT_LIMIT=1", connection).ExecuteNonQuery(); |
||||
resetSqlSelect = true; |
||||
} |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/Prepare2/*'/> |
||||
private void Prepare(int cursorPageSize) |
||||
{ |
||||
if (!connection.driver.Version.isAtLeast(5, 0, 0) && cursorPageSize > 0) |
||||
throw new InvalidOperationException("Nested commands are only supported on MySQL 5.0 and later"); |
||||
|
||||
using (new CommandTimer(Connection, CommandTimeout)) |
||||
{ |
||||
// if the length of the command text is zero, then just return |
||||
string psSQL = CommandText; |
||||
if (psSQL == null || |
||||
psSQL.Trim().Length == 0) |
||||
return; |
||||
|
||||
if (CommandType == CommandType.StoredProcedure) |
||||
statement = new StoredProcedure(this, CommandText); |
||||
else |
||||
statement = new PreparableStatement(this, CommandText); |
||||
|
||||
statement.Resolve(true); |
||||
statement.Prepare(); |
||||
} |
||||
} |
||||
|
||||
/// <include file='docs/mysqlcommand.xml' path='docs/Prepare/*'/> |
||||
public override void Prepare() |
||||
{ |
||||
if (connection == null) |
||||
throw new InvalidOperationException("The connection property has not been set."); |
||||
if (connection.State != ConnectionState.Open) |
||||
throw new InvalidOperationException("The connection is not open."); |
||||
if (connection.Settings.IgnorePrepare) |
||||
return; |
||||
|
||||
Prepare(0); |
||||
} |
||||
#endregion |
||||
|
||||
#region Async Methods |
||||
|
||||
internal delegate object AsyncDelegate(int type, CommandBehavior behavior); |
||||
internal AsyncDelegate caller = null; |
||||
internal Exception thrownException; |
||||
|
||||
private static string TrimSemicolons(string sql) |
||||
{ |
||||
int start = 0; |
||||
while (sql[start] == ';') |
||||
start++; |
||||
|
||||
int end = sql.Length - 1; |
||||
while (sql[end] == ';') |
||||
end--; |
||||
return sql.Substring(start, end-start+1); |
||||
} |
||||
|
||||
internal object AsyncExecuteWrapper(int type, CommandBehavior behavior) |
||||
{ |
||||
thrownException = null; |
||||
try |
||||
{ |
||||
if (type == 1) |
||||
return ExecuteReader(behavior); |
||||
return ExecuteNonQuery(); |
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
thrownException = ex; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initiates the asynchronous execution of the SQL statement or stored procedure |
||||
/// that is described by this <see cref="MySqlCommand"/>, and retrieves one or more |
||||
/// result sets from the server. |
||||
/// </summary> |
||||
/// <returns>An <see cref="IAsyncResult"/> that can be used to poll, wait for results, |
||||
/// or both; this value is also needed when invoking EndExecuteReader, |
||||
/// which returns a <see cref="MySqlDataReader"/> instance that can be used to retrieve |
||||
/// the returned rows. </returns> |
||||
public IAsyncResult BeginExecuteReader() |
||||
{ |
||||
return BeginExecuteReader(CommandBehavior.Default); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initiates the asynchronous execution of the SQL statement or stored procedure |
||||
/// that is described by this <see cref="MySqlCommand"/> using one of the |
||||
/// <b>CommandBehavior</b> values. |
||||
/// </summary> |
||||
/// <param name="behavior">One of the <see cref="CommandBehavior"/> values, indicating |
||||
/// options for statement execution and data retrieval.</param> |
||||
/// <returns>An <see cref="IAsyncResult"/> that can be used to poll, wait for results, |
||||
/// or both; this value is also needed when invoking EndExecuteReader, |
||||
/// which returns a <see cref="MySqlDataReader"/> instance that can be used to retrieve |
||||
/// the returned rows. </returns> |
||||
public IAsyncResult BeginExecuteReader(CommandBehavior behavior) |
||||
{ |
||||
if (caller != null) |
||||
throw new MySqlException(Resources.UnableToStartSecondAsyncOp); |
||||
|
||||
caller = new AsyncDelegate(AsyncExecuteWrapper); |
||||
asyncResult = caller.BeginInvoke(1, behavior, null, null); |
||||
return asyncResult; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Finishes asynchronous execution of a SQL statement, returning the requested |
||||
/// <see cref="MySqlDataReader"/>. |
||||
/// </summary> |
||||
/// <param name="result">The <see cref="IAsyncResult"/> returned by the call to |
||||
/// <see cref="BeginExecuteReader()"/>.</param> |
||||
/// <returns>A <b>MySqlDataReader</b> object that can be used to retrieve the requested rows. </returns> |
||||
public MySqlDataReader EndExecuteReader(IAsyncResult result) |
||||
{ |
||||
result.AsyncWaitHandle.WaitOne(); |
||||
AsyncDelegate c = caller; |
||||
caller = null; |
||||
if (thrownException != null) |
||||
throw thrownException; |
||||
return (MySqlDataReader)c.EndInvoke(result); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initiates the asynchronous execution of the SQL statement or stored procedure |
||||
/// that is described by this <see cref="MySqlCommand"/>. |
||||
/// </summary> |
||||
/// <param name="callback"> |
||||
/// An <see cref="AsyncCallback"/> delegate that is invoked when the command's |
||||
/// execution has completed. Pass a null reference (<b>Nothing</b> in Visual Basic) |
||||
/// to indicate that no callback is required.</param> |
||||
/// <param name="stateObject">A user-defined state object that is passed to the |
||||
/// callback procedure. Retrieve this object from within the callback procedure |
||||
/// using the <see cref="IAsyncResult.AsyncState"/> property.</param> |
||||
/// <returns>An <see cref="IAsyncResult"/> that can be used to poll or wait for results, |
||||
/// or both; this value is also needed when invoking <see cref="EndExecuteNonQuery"/>, |
||||
/// which returns the number of affected rows. </returns> |
||||
public IAsyncResult BeginExecuteNonQuery(AsyncCallback callback, object stateObject) |
||||
{ |
||||
if (caller != null) |
||||
throw new MySqlException(Resources.UnableToStartSecondAsyncOp); |
||||
|
||||
caller = new AsyncDelegate(AsyncExecuteWrapper); |
||||
asyncResult = caller.BeginInvoke(2, CommandBehavior.Default, |
||||
callback, stateObject); |
||||
return asyncResult; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Initiates the asynchronous execution of the SQL statement or stored procedure |
||||
/// that is described by this <see cref="MySqlCommand"/>. |
||||
/// </summary> |
||||
/// <returns>An <see cref="IAsyncResult"/> that can be used to poll or wait for results, |
||||
/// or both; this value is also needed when invoking <see cref="EndExecuteNonQuery"/>, |
||||
/// which returns the number of affected rows. </returns> |
||||
public IAsyncResult BeginExecuteNonQuery() |
||||
{ |
||||
if (caller != null) |
||||
throw new MySqlException(Resources.UnableToStartSecondAsyncOp); |
||||
|
||||
caller = new AsyncDelegate(AsyncExecuteWrapper); |
||||
asyncResult = caller.BeginInvoke(2, CommandBehavior.Default, null, null); |
||||
return asyncResult; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Finishes asynchronous execution of a SQL statement. |
||||
/// </summary> |
||||
/// <param name="asyncResult">The <see cref="IAsyncResult"/> returned by the call |
||||
/// to <see cref="BeginExecuteNonQuery()"/>.</param> |
||||
/// <returns></returns> |
||||
public int EndExecuteNonQuery(IAsyncResult asyncResult) |
||||
{ |
||||
asyncResult.AsyncWaitHandle.WaitOne(); |
||||
AsyncDelegate c = caller; |
||||
caller = null; |
||||
if (thrownException != null) |
||||
throw thrownException; |
||||
return (int)c.EndInvoke(asyncResult); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Private Methods |
||||
|
||||
/* private ArrayList PrepareSqlBuffers(string sql) |
||||
{ |
||||
ArrayList buffers = new ArrayList(); |
||||
MySqlStreamWriter writer = new MySqlStreamWriter(new MemoryStream(), connection.Encoding); |
||||
writer.Version = connection.driver.Version; |
||||
|
||||
// if we are executing as a stored procedure, then we need to add the call |
||||
// keyword. |
||||
if (CommandType == CommandType.StoredProcedure) |
||||
{ |
||||
if (storedProcedure == null) |
||||
storedProcedure = new StoredProcedure(this); |
||||
sql = storedProcedure.Prepare( CommandText ); |
||||
} |
||||
|
||||
// tokenize the SQL |
||||
sql = sql.TrimStart(';').TrimEnd(';'); |
||||
ArrayList tokens = TokenizeSql( sql ); |
||||
|
||||
foreach (string token in tokens) |
||||
{ |
||||
if (token.Trim().Length == 0) continue; |
||||
if (token == ";" && ! connection.driver.SupportsBatch) |
||||
{ |
||||
MemoryStream ms = (MemoryStream)writer.Stream; |
||||
if (ms.Length > 0) |
||||
buffers.Add( ms ); |
||||
|
||||
writer = new MySqlStreamWriter(new MemoryStream(), connection.Encoding); |
||||
writer.Version = connection.driver.Version; |
||||
continue; |
||||
} |
||||
else if (token[0] == parameters.ParameterMarker) |
||||
{ |
||||
if (SerializeParameter(writer, token)) continue; |
||||
} |
||||
|
||||
// our fall through case is to write the token to the byte stream |
||||
writer.WriteStringNoNull(token); |
||||
} |
||||
|
||||
// capture any buffer that is left over |
||||
MemoryStream mStream = (MemoryStream)writer.Stream; |
||||
if (mStream.Length > 0) |
||||
buffers.Add( mStream ); |
||||
|
||||
return buffers; |
||||
}*/ |
||||
|
||||
internal long EstimatedSize() |
||||
{ |
||||
long size = CommandText.Length; |
||||
foreach (MySqlParameter parameter in Parameters) |
||||
size += parameter.EstimatedSize(); |
||||
return size; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region ICloneable |
||||
|
||||
/// <summary> |
||||
/// Creates a clone of this MySqlCommand object. CommandText, Connection, and Transaction properties |
||||
/// are included as well as the entire parameter list. |
||||
/// </summary> |
||||
/// <returns>The cloned MySqlCommand object</returns> |
||||
public MySqlCommand Clone() |
||||
{ |
||||
MySqlCommand clone = new MySqlCommand(cmdText, connection, curTransaction); |
||||
clone.CommandType = CommandType; |
||||
clone.CommandTimeout = CommandTimeout; |
||||
clone.batchableCommandText = batchableCommandText; |
||||
clone.UpdatedRowSource = UpdatedRowSource; |
||||
|
||||
foreach (MySqlParameter p in parameters) |
||||
{ |
||||
clone.Parameters.Add(p.Clone()); |
||||
} |
||||
return clone; |
||||
} |
||||
|
||||
object ICloneable.Clone() |
||||
{ |
||||
return this.Clone(); |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Batching support |
||||
|
||||
internal void AddToBatch(MySqlCommand command) |
||||
{ |
||||
if (batch == null) |
||||
batch = new List<MySqlCommand>(); |
||||
batch.Add(command); |
||||
} |
||||
|
||||
internal string GetCommandTextForBatching() |
||||
{ |
||||
if (batchableCommandText == null) |
||||
{ |
||||
// if the command starts with insert and is "simple" enough, then |
||||
// we can use the multi-value form of insert |
||||
if (String.Compare(CommandText.Substring(0, 6), "INSERT", true) == 0) |
||||
{ |
||||
MySqlCommand cmd = new MySqlCommand("SELECT @@sql_mode", Connection); |
||||
string sql_mode = cmd.ExecuteScalar().ToString().ToUpper(CultureInfo.InvariantCulture); |
||||
MySqlTokenizer tokenizer = new MySqlTokenizer(CommandText); |
||||
tokenizer.AnsiQuotes = sql_mode.IndexOf("ANSI_QUOTES") != -1; |
||||
tokenizer.BackslashEscapes = sql_mode.IndexOf("NO_BACKSLASH_ESCAPES") == -1; |
||||
string token = tokenizer.NextToken().ToLower(CultureInfo.InvariantCulture); |
||||
while (token != null) |
||||
{ |
||||
if (token.ToUpper(CultureInfo.InvariantCulture) == "VALUES" && |
||||
!tokenizer.Quoted) |
||||
{ |
||||
token = tokenizer.NextToken(); |
||||
Debug.Assert(token == "("); |
||||
while (token != null && token != ")") |
||||
{ |
||||
batchableCommandText += token; |
||||
token = tokenizer.NextToken(); |
||||
} |
||||
if (token != null) |
||||
batchableCommandText += token; |
||||
token = tokenizer.NextToken(); |
||||
if (token != null && (token == "," || |
||||
token.ToUpper(CultureInfo.InvariantCulture) == "ON")) |
||||
{ |
||||
batchableCommandText = null; |
||||
break; |
||||
} |
||||
} |
||||
token = tokenizer.NextToken(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return batchableCommandText; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
protected override void Dispose(bool disposing) |
||||
{ |
||||
if (disposing) |
||||
{ |
||||
if (statement != null && statement.IsPrepared) |
||||
statement.CloseStatement(); |
||||
} |
||||
base.Dispose(disposing); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets a value indicating whether the command object should be visible in a Windows Form Designer control. |
||||
/// </summary> |
||||
#if !CF |
||||
[Browsable(false)] |
||||
#endif |
||||
public override bool DesignTimeVisible |
||||
{ |
||||
get |
||||
{ |
||||
return designTimeVisible; |
||||
} |
||||
set |
||||
{ |
||||
designTimeVisible = value; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets how command results are applied to the DataRow when used by the |
||||
/// Update method of the DbDataAdapter. |
||||
/// </summary> |
||||
public override UpdateRowSource UpdatedRowSource |
||||
{ |
||||
get |
||||
{ |
||||
return updatedRowSource; |
||||
} |
||||
set |
||||
{ |
||||
updatedRowSource = value; |
||||
} |
||||
} |
||||
|
||||
protected override DbParameter CreateDbParameter() |
||||
{ |
||||
return new MySqlParameter(); |
||||
} |
||||
|
||||
protected override DbConnection DbConnection |
||||
{ |
||||
get { return Connection; } |
||||
set { Connection = (MySqlConnection)value; } |
||||
} |
||||
|
||||
protected override DbParameterCollection DbParameterCollection |
||||
{ |
||||
get { return Parameters; } |
||||
} |
||||
|
||||
protected override DbTransaction DbTransaction |
||||
{ |
||||
get { return Transaction; } |
||||
set { Transaction = (MySqlTransaction)value; } |
||||
} |
||||
|
||||
protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) |
||||
{ |
||||
return ExecuteReader(behavior); |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,76 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
internal class Cache<KeyType, ValueType> |
||||
{ |
||||
private int _capacity; |
||||
private Queue<KeyType> _keyQ; |
||||
private Dictionary<KeyType, ValueType> _contents; |
||||
|
||||
public Cache(int initialCapacity, int capacity) |
||||
{ |
||||
_capacity = capacity; |
||||
_contents = new Dictionary<KeyType, ValueType>(initialCapacity); |
||||
|
||||
if (capacity > 0) |
||||
_keyQ = new Queue<KeyType>(initialCapacity); |
||||
} |
||||
|
||||
public ValueType this[KeyType key] |
||||
{ |
||||
get |
||||
{ |
||||
ValueType val; |
||||
if (_contents.TryGetValue(key, out val)) |
||||
return val; |
||||
else |
||||
return default(ValueType); |
||||
} |
||||
set { InternalAdd(key, value); } |
||||
} |
||||
|
||||
public void Add(KeyType key, ValueType value) |
||||
{ |
||||
InternalAdd(key, value); |
||||
} |
||||
|
||||
private void InternalAdd(KeyType key, ValueType value) |
||||
{ |
||||
if (!_contents.ContainsKey(key)) |
||||
{ |
||||
|
||||
if (_capacity > 0) |
||||
{ |
||||
_keyQ.Enqueue(key); |
||||
|
||||
if (_keyQ.Count > _capacity) |
||||
_contents.Remove(_keyQ.Dequeue()); |
||||
} |
||||
} |
||||
|
||||
_contents[key] = value; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,170 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Collections; |
||||
using System.Text; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
internal class ContextString |
||||
{ |
||||
string contextMarkers; |
||||
bool escapeBackslash; |
||||
|
||||
// Create a private ctor so the compiler doesn't give us a default one |
||||
public ContextString(string contextMarkers, bool escapeBackslash) |
||||
{ |
||||
this.contextMarkers = contextMarkers; |
||||
this.escapeBackslash = escapeBackslash; |
||||
} |
||||
|
||||
public string ContextMarkers |
||||
{ |
||||
get { return contextMarkers; } |
||||
set { contextMarkers = value; } |
||||
} |
||||
|
||||
public int IndexOf(string src, string target) |
||||
{ |
||||
return IndexOf(src, target, 0); |
||||
} |
||||
|
||||
public int IndexOf(string src, string target, int startIndex) |
||||
{ |
||||
int index = src.IndexOf(target, startIndex); |
||||
while (index != -1) |
||||
{ |
||||
if (!IndexInQuotes(src, index, startIndex)) break; |
||||
index = src.IndexOf(target, index + 1); |
||||
} |
||||
return index; |
||||
} |
||||
|
||||
private bool IndexInQuotes(string src, int index, int startIndex) |
||||
{ |
||||
char contextMarker = Char.MinValue; |
||||
bool escaped = false; |
||||
|
||||
for (int i = startIndex; i < index; i++) |
||||
{ |
||||
char c = src[i]; |
||||
|
||||
int contextIndex = contextMarkers.IndexOf(c); |
||||
|
||||
// if we have found the closing marker for our open marker, then close the context |
||||
if (contextIndex > -1 && contextMarker == contextMarkers[contextIndex] && !escaped) |
||||
contextMarker = Char.MinValue; |
||||
|
||||
// if we have found a context marker and we are not in a context yet, then start one |
||||
else if (contextMarker == Char.MinValue && contextIndex > -1 && !escaped) |
||||
contextMarker = c; |
||||
|
||||
else if (c == '\\' && escapeBackslash) |
||||
escaped = !escaped; |
||||
} |
||||
return contextMarker != Char.MinValue || escaped; |
||||
} |
||||
|
||||
public int IndexOf(string src, char target) |
||||
{ |
||||
char contextMarker = Char.MinValue; |
||||
bool escaped = false; |
||||
int pos = 0; |
||||
|
||||
foreach (char c in src) |
||||
{ |
||||
int contextIndex = contextMarkers.IndexOf(c); |
||||
|
||||
// if we have found the closing marker for our open marker, then close the context |
||||
if (contextIndex > -1 && contextMarker == contextMarkers[contextIndex] && !escaped) |
||||
contextMarker = Char.MinValue; |
||||
|
||||
// if we have found a context marker and we are not in a context yet, then start one |
||||
else if (contextMarker == Char.MinValue && contextIndex > -1 && !escaped) |
||||
contextMarker = c; |
||||
|
||||
else if (contextMarker == Char.MinValue && c == target) |
||||
return pos; |
||||
else if (c == '\\' && escapeBackslash) |
||||
escaped = !escaped; |
||||
pos++; |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
public string[] Split(string src, string delimiters) |
||||
{ |
||||
ArrayList parts = new ArrayList(); |
||||
StringBuilder sb = new StringBuilder(); |
||||
bool escaped = false; |
||||
|
||||
char contextMarker = Char.MinValue; |
||||
|
||||
foreach (char c in src) |
||||
{ |
||||
if (delimiters.IndexOf(c) != -1 && !escaped) |
||||
{ |
||||
if (contextMarker != Char.MinValue) |
||||
sb.Append(c); |
||||
else |
||||
{ |
||||
if (sb.Length > 0) |
||||
{ |
||||
parts.Add( sb.ToString() ); |
||||
sb.Remove( 0, sb.Length ); |
||||
} |
||||
} |
||||
} |
||||
else if (c == '\\' && escapeBackslash) |
||||
escaped = !escaped; |
||||
else |
||||
{ |
||||
int contextIndex = contextMarkers.IndexOf(c); |
||||
if (!escaped && contextIndex != -1) |
||||
{ |
||||
// if we have found the closing marker for our open |
||||
// marker, then close the context |
||||
if ((contextIndex % 2) == 1) |
||||
{ |
||||
if (contextMarker == contextMarkers[contextIndex - 1]) |
||||
contextMarker = Char.MinValue; |
||||
} |
||||
else |
||||
{ |
||||
// if the opening and closing context markers are |
||||
// the same then we will always find the opening |
||||
// marker. |
||||
if (contextMarker == contextMarkers[contextIndex + 1]) |
||||
contextMarker = Char.MinValue; |
||||
else if (contextMarker == Char.MinValue) |
||||
contextMarker = c; |
||||
} |
||||
} |
||||
|
||||
sb.Append( c ); |
||||
} |
||||
} |
||||
if (sb.Length > 0) |
||||
parts.Add( sb.ToString() ); |
||||
return (string[])parts.ToArray( typeof(string) ); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,180 @@ |
||||
// Copyright (c) 2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Net.Sockets; |
||||
|
||||
internal class MyNetworkStream : NetworkStream |
||||
{ |
||||
/// <summary> |
||||
/// Wrapper around NetworkStream. |
||||
/// |
||||
/// MyNetworkStream is equivalent to NetworkStream, except |
||||
/// 1. It throws TimeoutException if read or write timeout occurs, instead |
||||
/// of IOException, to match behavior of other streams (named pipe and |
||||
/// shared memory). This property comes handy in TimedStream. |
||||
/// |
||||
/// 2. It implements workarounds for WSAEWOULDBLOCK errors, that can start |
||||
/// occuring after stream has times out. For a discussion about the CLR bug, |
||||
/// refer to http://tinyurl.com/lhgpyf. This error should never occur, as |
||||
/// we're not using asynchronous operations, but apparerntly it does occur |
||||
/// directly after timeout has expired. |
||||
/// The workaround is hinted in the URL above and implemented like this: |
||||
/// For each IO operation, if it throws WSAEWOULDBLOCK, we explicitely set |
||||
/// the socket to Blocking and retry the operation once again. |
||||
/// </summary> |
||||
const int MaxRetryCount = 2; |
||||
Socket socket; |
||||
|
||||
public MyNetworkStream(Socket socket, bool ownsSocket) |
||||
: base(socket, ownsSocket) |
||||
{ |
||||
this.socket = socket; |
||||
} |
||||
|
||||
bool IsTimeoutException(SocketException e) |
||||
{ |
||||
#if CF |
||||
return (e.NativeErrorCode == 10060); |
||||
#else |
||||
return (e.SocketErrorCode == SocketError.TimedOut); |
||||
#endif |
||||
} |
||||
|
||||
bool IsWouldBlockException(SocketException e) |
||||
{ |
||||
#if CF |
||||
return (e.NativeErrorCode == 10035); |
||||
#else |
||||
return (e.SocketErrorCode == SocketError.WouldBlock); |
||||
#endif |
||||
} |
||||
|
||||
|
||||
void HandleOrRethrowException(Exception e) |
||||
{ |
||||
Exception currentException = e; |
||||
while (currentException != null) |
||||
{ |
||||
if (currentException is SocketException) |
||||
{ |
||||
SocketException socketException = (SocketException)currentException; |
||||
if (IsWouldBlockException(socketException)) |
||||
{ |
||||
// Workaround for WSAEWOULDBLOCK |
||||
socket.Blocking= true; |
||||
// return to give the caller possibility to retry the call |
||||
return; |
||||
} |
||||
else if (IsTimeoutException(socketException)) |
||||
{ |
||||
throw new TimeoutException(socketException.Message, e); |
||||
} |
||||
|
||||
} |
||||
currentException = currentException.InnerException; |
||||
} |
||||
throw (e); |
||||
} |
||||
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) |
||||
{ |
||||
int retry = 0; |
||||
Exception exception = null; |
||||
do |
||||
{ |
||||
try |
||||
{ |
||||
return base.Read(buffer, offset, count); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
exception = e; |
||||
HandleOrRethrowException(e); |
||||
} |
||||
} |
||||
while (++retry < MaxRetryCount); |
||||
throw exception; |
||||
} |
||||
|
||||
public override int ReadByte() |
||||
{ |
||||
int retry = 0; |
||||
Exception exception = null; |
||||
do |
||||
{ |
||||
try |
||||
{ |
||||
return base.ReadByte(); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
exception = e; |
||||
HandleOrRethrowException(e); |
||||
} |
||||
} |
||||
while (++retry < MaxRetryCount); |
||||
throw exception; |
||||
} |
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) |
||||
{ |
||||
int retry = 0; |
||||
Exception exception = null; |
||||
do |
||||
{ |
||||
try |
||||
{ |
||||
base.Write(buffer, offset, count); |
||||
return; |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
exception = e; |
||||
HandleOrRethrowException(e); |
||||
} |
||||
} |
||||
while (++retry < MaxRetryCount); |
||||
throw exception; |
||||
} |
||||
|
||||
public override void Flush() |
||||
{ |
||||
int retry = 0; |
||||
Exception exception = null; |
||||
do |
||||
{ |
||||
try |
||||
{ |
||||
base.Flush(); |
||||
return; |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
exception = e; |
||||
HandleOrRethrowException(e); |
||||
} |
||||
} |
||||
while (++retry < MaxRetryCount); |
||||
throw exception; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,312 @@ |
||||
// Copyright (c) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Text; |
||||
using System.IO; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
internal class MySqlTokenizer |
||||
{ |
||||
private string sql; |
||||
|
||||
private int startIndex; |
||||
private int stopIndex; |
||||
|
||||
private bool ansiQuotes; |
||||
private bool backslashEscapes; |
||||
private bool returnComments; |
||||
private bool multiLine; |
||||
|
||||
private bool quoted; |
||||
private bool isComment; |
||||
|
||||
private int pos; |
||||
|
||||
public MySqlTokenizer() |
||||
{ |
||||
backslashEscapes = true; |
||||
multiLine = true; |
||||
pos = 0; |
||||
} |
||||
|
||||
public MySqlTokenizer(string input) : this() |
||||
{ |
||||
sql = input; |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public string Text |
||||
{ |
||||
get { return sql; } |
||||
set { sql = value; pos = 0; } |
||||
} |
||||
|
||||
public bool AnsiQuotes |
||||
{ |
||||
get { return ansiQuotes; } |
||||
set { ansiQuotes = value; } |
||||
} |
||||
|
||||
public bool BackslashEscapes |
||||
{ |
||||
get { return backslashEscapes; } |
||||
set { backslashEscapes = value; } |
||||
} |
||||
|
||||
public bool MultiLine |
||||
{ |
||||
get { return multiLine; } |
||||
set { multiLine = value; } |
||||
} |
||||
|
||||
public bool Quoted |
||||
{ |
||||
get { return quoted; } |
||||
private set { quoted = value; } |
||||
} |
||||
|
||||
public bool IsComment |
||||
{ |
||||
get { return isComment; } |
||||
} |
||||
|
||||
public int StartIndex |
||||
{ |
||||
get { return startIndex; } |
||||
set { startIndex = value; } |
||||
} |
||||
|
||||
public int StopIndex |
||||
{ |
||||
get { return stopIndex; } |
||||
set { stopIndex = value; } |
||||
} |
||||
|
||||
public int Position |
||||
{ |
||||
get { return pos; } |
||||
set { pos = value; } |
||||
} |
||||
|
||||
public bool ReturnComments |
||||
{ |
||||
get { return returnComments; } |
||||
set { returnComments = value; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public List<string> GetAllTokens() |
||||
{ |
||||
List<string> tokens = new List<string>(); |
||||
string token = NextToken(); |
||||
while (token != null) |
||||
{ |
||||
tokens.Add(token); |
||||
token = NextToken(); |
||||
} |
||||
return tokens; |
||||
} |
||||
|
||||
public string NextToken() |
||||
{ |
||||
while (FindToken()) |
||||
{ |
||||
string token = sql.Substring(startIndex, stopIndex - startIndex).Trim(); |
||||
return token; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public string NextParameter() |
||||
{ |
||||
while (FindToken()) |
||||
{ |
||||
if ((stopIndex - startIndex) < 2) continue; |
||||
string token = sql.Substring(startIndex, stopIndex - startIndex).Trim(); |
||||
char c1 = sql[startIndex]; |
||||
char c2 = sql[startIndex+1]; |
||||
if (c1 == '?' || |
||||
(c1 == '@' && c2 != '@')) |
||||
return sql.Substring(startIndex, stopIndex - startIndex); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public bool FindToken() |
||||
{ |
||||
isComment = quoted = false; // reset our flags |
||||
startIndex = stopIndex = -1; |
||||
|
||||
while (pos < sql.Length) |
||||
{ |
||||
char c = sql[pos++]; |
||||
if (Char.IsWhiteSpace(c)) continue; |
||||
|
||||
if (c == '`' || c == '\'' || c == '"') //(c == '"' && AnsiQuotes)) |
||||
ReadQuotedToken(c); |
||||
else if (c == '#' || c == '-' || c == '/') |
||||
{ |
||||
if (!ReadComment(c)) |
||||
ReadSpecialToken(); |
||||
} |
||||
else |
||||
ReadUnquotedToken(); |
||||
if (startIndex != -1) return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public string ReadParenthesis() |
||||
{ |
||||
StringBuilder sb = new StringBuilder("("); |
||||
int start = StartIndex; |
||||
string token = NextToken(); |
||||
while (true) |
||||
{ |
||||
if (token == null) |
||||
throw new InvalidOperationException("Unable to parse SQL"); |
||||
sb.Append(token); |
||||
if (token == ")" && !Quoted) break; |
||||
token = NextToken(); |
||||
} |
||||
return sb.ToString(); |
||||
} |
||||
|
||||
private bool ReadComment(char c) |
||||
{ |
||||
// make sure the comment starts correctly |
||||
if (c == '/' && (pos >= sql.Length || sql[pos] != '*')) return false; |
||||
if (c == '-' && ((pos + 1) >= sql.Length || sql[pos] != '-' || sql[pos + 1] != ' ')) return false; |
||||
|
||||
string endingPattern = "\n"; |
||||
if (sql[pos] == '*') |
||||
endingPattern = "*/"; |
||||
|
||||
int startingIndex = pos-1; |
||||
|
||||
int index = sql.IndexOf(endingPattern, pos); |
||||
if (index == -1) |
||||
index = sql.Length - 1; |
||||
else |
||||
index += endingPattern.Length; |
||||
|
||||
pos = index; |
||||
if (ReturnComments) |
||||
{ |
||||
startIndex = startingIndex; |
||||
stopIndex = index; |
||||
isComment = true; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
private void CalculatePosition(int start, int stop) |
||||
{ |
||||
startIndex = start; |
||||
stopIndex = stop; |
||||
if (!MultiLine) return; |
||||
} |
||||
|
||||
private void ReadUnquotedToken() |
||||
{ |
||||
startIndex = pos-1; |
||||
|
||||
if (!IsSpecialCharacter(sql[startIndex])) |
||||
{ |
||||
while (pos < sql.Length) |
||||
{ |
||||
char c = sql[pos]; |
||||
if (Char.IsWhiteSpace(c)) break; |
||||
if (IsSpecialCharacter(c)) break; |
||||
pos++; |
||||
} |
||||
} |
||||
|
||||
Quoted = false; |
||||
stopIndex = pos; |
||||
} |
||||
|
||||
private void ReadSpecialToken() |
||||
{ |
||||
startIndex = pos - 1; |
||||
|
||||
Debug.Assert(IsSpecialCharacter(sql[startIndex])); |
||||
|
||||
stopIndex = pos; |
||||
Quoted = false; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Read a single quoted identifier from the stream |
||||
/// </summary> |
||||
/// <param name="quoteChar"></param> |
||||
/// <returns></returns> |
||||
private void ReadQuotedToken(char quoteChar) |
||||
{ |
||||
startIndex = pos-1; |
||||
bool escaped = false; |
||||
|
||||
bool found = false; |
||||
while (pos < sql.Length) |
||||
{ |
||||
char c = sql[pos]; |
||||
|
||||
if (c == quoteChar && !escaped) |
||||
{ |
||||
found = true; |
||||
break; |
||||
} |
||||
|
||||
if (escaped) |
||||
escaped = false; |
||||
else if (c == '\\' && BackslashEscapes) |
||||
escaped = true; |
||||
pos++; |
||||
} |
||||
if (found) pos++; |
||||
Quoted = found; |
||||
stopIndex = pos; |
||||
} |
||||
|
||||
private bool IsQuoteChar(char c) |
||||
{ |
||||
return c == '`' || c == '\'' || c == '\"'; |
||||
} |
||||
|
||||
private bool IsParameterMarker(char c) |
||||
{ |
||||
return c == '@' || c == '?'; |
||||
} |
||||
|
||||
private bool IsSpecialCharacter(char c) |
||||
{ |
||||
if (Char.IsLetterOrDigit(c) || |
||||
c == '$' || c == '_' || c == '.') return false; |
||||
if (IsParameterMarker(c)) return false; |
||||
return true; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,236 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.IO; |
||||
using MySql.Data.MySqlClient; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using Microsoft.Win32.SafeHandles; |
||||
using System.Threading; |
||||
using System.Diagnostics; |
||||
using System.Runtime.InteropServices; |
||||
using System.ComponentModel; |
||||
|
||||
|
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for API. |
||||
/// </summary> |
||||
internal class NamedPipeStream : Stream |
||||
{ |
||||
SafeFileHandle handle; |
||||
Stream fileStream; |
||||
int readTimeout = Timeout.Infinite; |
||||
int writeTimeout = Timeout.Infinite; |
||||
const int ERROR_PIPE_BUSY = 231; |
||||
const int ERROR_SEM_TIMEOUT = 121; |
||||
|
||||
public NamedPipeStream(string path, FileAccess mode, uint timeout) |
||||
{ |
||||
Open(path, mode, timeout); |
||||
} |
||||
|
||||
void CancelIo() |
||||
{ |
||||
bool ok = NativeMethods.CancelIo(handle.DangerousGetHandle()); |
||||
if (!ok) |
||||
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); |
||||
} |
||||
public void Open( string path, FileAccess mode ,uint timeout ) |
||||
{ |
||||
IntPtr nativeHandle; |
||||
for (; ; ) |
||||
{ |
||||
nativeHandle = NativeMethods.CreateFile(path, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, |
||||
0, null, NativeMethods.OPEN_EXISTING, NativeMethods.FILE_FLAG_OVERLAPPED, 0); |
||||
if (nativeHandle != IntPtr.Zero) |
||||
break; |
||||
|
||||
if (Marshal.GetLastWin32Error() != ERROR_PIPE_BUSY) |
||||
{ |
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), |
||||
"Error opening pipe"); |
||||
} |
||||
LowResolutionStopwatch sw = LowResolutionStopwatch.StartNew(); |
||||
bool success = NativeMethods.WaitNamedPipe(path, timeout); |
||||
sw.Stop(); |
||||
if (!success) |
||||
{ |
||||
if (timeout < sw.ElapsedMilliseconds || |
||||
Marshal.GetLastWin32Error() == ERROR_SEM_TIMEOUT) |
||||
{ |
||||
throw new TimeoutException("Timeout waiting for named pipe"); |
||||
} |
||||
else |
||||
{ |
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), |
||||
"Error waiting for pipe"); |
||||
} |
||||
} |
||||
timeout -= (uint)sw.ElapsedMilliseconds; |
||||
} |
||||
handle = new SafeFileHandle(nativeHandle, true); |
||||
fileStream = new FileStream(handle, mode, 4096, true); |
||||
} |
||||
|
||||
public override bool CanRead |
||||
{ |
||||
get { return fileStream.CanRead; } |
||||
} |
||||
|
||||
public override bool CanWrite |
||||
{ |
||||
get { return fileStream.CanWrite; } |
||||
} |
||||
|
||||
public override bool CanSeek |
||||
{ |
||||
get { throw new NotSupportedException(Resources.NamedPipeNoSeek); } |
||||
} |
||||
|
||||
public override long Length |
||||
{ |
||||
get { throw new NotSupportedException(Resources.NamedPipeNoSeek); } |
||||
} |
||||
|
||||
public override long Position |
||||
{ |
||||
get { throw new NotSupportedException(Resources.NamedPipeNoSeek); } |
||||
set { } |
||||
} |
||||
|
||||
public override void Flush() |
||||
{ |
||||
fileStream.Flush(); |
||||
} |
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) |
||||
{ |
||||
if(readTimeout == Timeout.Infinite) |
||||
{ |
||||
return fileStream.Read(buffer, offset, count); |
||||
} |
||||
IAsyncResult result = fileStream.BeginRead(buffer, offset, count, null, null); |
||||
if (result.CompletedSynchronously) |
||||
return fileStream.EndRead(result); |
||||
|
||||
if (!result.AsyncWaitHandle.WaitOne(readTimeout)) |
||||
{ |
||||
CancelIo(); |
||||
throw new TimeoutException("Timeout in named pipe read"); |
||||
} |
||||
return fileStream.EndRead(result); |
||||
} |
||||
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) |
||||
{ |
||||
if (writeTimeout == Timeout.Infinite) |
||||
{ |
||||
fileStream.Write(buffer, offset, count); |
||||
return; |
||||
} |
||||
IAsyncResult result = fileStream.BeginWrite(buffer, offset, count, null, null); |
||||
if (result.CompletedSynchronously) |
||||
{ |
||||
fileStream.EndWrite(result); |
||||
} |
||||
|
||||
if (!result.AsyncWaitHandle.WaitOne(readTimeout)) |
||||
{ |
||||
CancelIo(); |
||||
throw new TimeoutException("Timeout in named pipe write"); |
||||
} |
||||
fileStream.EndWrite(result); |
||||
} |
||||
|
||||
public override void Close() |
||||
{ |
||||
if (handle != null && !handle.IsInvalid && !handle.IsClosed) |
||||
{ |
||||
fileStream.Close(); |
||||
try |
||||
{ |
||||
handle.Close(); |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
|
||||
public override void SetLength(long length) |
||||
{ |
||||
throw new NotSupportedException(Resources.NamedPipeNoSetLength); |
||||
} |
||||
|
||||
|
||||
public override bool CanTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
public override int ReadTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return readTimeout; |
||||
} |
||||
set |
||||
{ |
||||
readTimeout = value; |
||||
} |
||||
} |
||||
|
||||
public override int WriteTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return writeTimeout; |
||||
} |
||||
set |
||||
{ |
||||
writeTimeout = value; |
||||
} |
||||
} |
||||
|
||||
public override long Seek( long offset, SeekOrigin origin ) |
||||
{ |
||||
throw new NotSupportedException(Resources.NamedPipeNoSeek); |
||||
} |
||||
|
||||
internal static Stream Create(string pipeName, string hostname, uint timeout) |
||||
{ |
||||
string pipePath; |
||||
if (0 == String.Compare(hostname, "localhost", true)) |
||||
pipePath = @"\\.\pipe\" + pipeName; |
||||
else |
||||
pipePath = String.Format(@"\\{0}\pipe\{1}", hostname, pipeName); |
||||
return new NamedPipeStream(pipePath, FileAccess.ReadWrite, timeout); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
@ -0,0 +1,154 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Runtime.InteropServices; |
||||
using System.Threading; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
internal class NativeMethods |
||||
{ |
||||
// Keep the compiler from generating a default ctor |
||||
private NativeMethods() |
||||
{ |
||||
} |
||||
|
||||
//Constants for dwDesiredAccess: |
||||
public const UInt32 GENERIC_READ = 0x80000000; |
||||
public const UInt32 GENERIC_WRITE = 0x40000000; |
||||
|
||||
//Constants for return value: |
||||
public const Int32 INVALIDpipeHandle_VALUE = -1; |
||||
|
||||
//Constants for dwFlagsAndAttributes: |
||||
public const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000; |
||||
public const UInt32 FILE_FLAG_NO_BUFFERING = 0x20000000; |
||||
|
||||
//Constants for dwCreationDisposition: |
||||
public const UInt32 OPEN_EXISTING = 3; |
||||
|
||||
[StructLayout(LayoutKind.Sequential)] |
||||
public class SecurityAttributes |
||||
{ |
||||
public SecurityAttributes() |
||||
{ |
||||
Length = Marshal.SizeOf(typeof(SecurityAttributes)); |
||||
} |
||||
public int Length; |
||||
public IntPtr securityDescriptor = IntPtr.Zero; |
||||
public bool inheritHandle; |
||||
} |
||||
|
||||
[DllImport("Kernel32", CharSet=CharSet.Unicode)] |
||||
static extern public IntPtr CreateFile( |
||||
String fileName, |
||||
uint desiredAccess, |
||||
uint shareMode, |
||||
SecurityAttributes securityAttributes, |
||||
uint creationDisposition, |
||||
uint flagsAndAttributes, |
||||
uint templateFile); |
||||
|
||||
[return:MarshalAs(UnmanagedType.Bool)] |
||||
[DllImport("kernel32.dll", EntryPoint="PeekNamedPipe", SetLastError=true)] |
||||
static extern public bool PeekNamedPipe(IntPtr handle, |
||||
byte[] buffer, |
||||
uint nBufferSize, |
||||
ref uint bytesRead, |
||||
ref uint bytesAvail, |
||||
ref uint BytesLeftThisMessage); |
||||
|
||||
[return:MarshalAs(UnmanagedType.Bool)] |
||||
[DllImport("kernel32.dll", SetLastError=true)] |
||||
static extern public bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, |
||||
out uint lpNumberOfBytesRead, IntPtr lpOverlapped); |
||||
|
||||
[return:MarshalAs(UnmanagedType.Bool)] |
||||
[DllImport("Kernel32")] |
||||
public static extern bool WriteFile(IntPtr hFile, [In]byte[] buffer, |
||||
uint numberOfBytesToWrite, out uint numberOfBytesWritten, IntPtr lpOverlapped); |
||||
|
||||
[return:MarshalAs(UnmanagedType.Bool)] |
||||
[DllImport("kernel32.dll", SetLastError=true)] |
||||
public static extern bool CloseHandle(IntPtr handle); |
||||
|
||||
[return: MarshalAs(UnmanagedType.Bool)] |
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern bool CancelIo(IntPtr handle); |
||||
|
||||
[return:MarshalAs(UnmanagedType.Bool)] |
||||
[DllImport("kernel32.dll", SetLastError=true)] |
||||
public static extern bool FlushFileBuffers(IntPtr handle); |
||||
|
||||
[DllImport("kernel32.dll", CharSet=CharSet.Unicode)] |
||||
public static extern IntPtr OpenEvent(uint dwDesiredAccess, |
||||
[MarshalAs(UnmanagedType.Bool)]bool bInheritHandle, |
||||
string lpName); |
||||
|
||||
[DllImport("kernel32.dll", CharSet=CharSet.Unicode)] |
||||
public static extern IntPtr OpenFileMapping(uint dwDesiredAccess, |
||||
[MarshalAs(UnmanagedType.Bool)]bool bInheritHandle, |
||||
string lpName); |
||||
|
||||
[DllImport("kernel32.dll")] |
||||
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint |
||||
dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, |
||||
IntPtr dwNumberOfBytesToMap); |
||||
|
||||
[DllImport("kernel32.dll")] |
||||
[return: MarshalAs(UnmanagedType.Bool)] |
||||
public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); |
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern int FlushViewOfFile(IntPtr address, uint numBytes); |
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)] |
||||
public static extern bool WaitNamedPipe(string namedPipeName, uint timeOut); |
||||
#region Winsock functions |
||||
|
||||
// SOcket routines |
||||
[DllImport("ws2_32.dll", SetLastError=true)] |
||||
static extern public IntPtr socket(int af, int type, int protocol); |
||||
|
||||
[DllImport("ws2_32.dll", SetLastError=true)] |
||||
static extern public int ioctlsocket(IntPtr socket, uint cmd, ref UInt32 arg); |
||||
|
||||
[DllImport("ws2_32.dll", SetLastError=true)] |
||||
public static extern int WSAIoctl(IntPtr s, uint dwIoControlCode, byte[] inBuffer, uint cbInBuffer, |
||||
byte[] outBuffer, uint cbOutBuffer, IntPtr lpcbBytesReturned, IntPtr lpOverlapped, |
||||
IntPtr lpCompletionRoutine); |
||||
|
||||
[DllImport("ws2_32.dll", SetLastError=true)] |
||||
static extern public int WSAGetLastError(); |
||||
|
||||
[DllImport("ws2_32.dll", SetLastError=true)] |
||||
static extern public int connect(IntPtr socket, byte[] addr, int addrlen); |
||||
|
||||
[DllImport("ws2_32.dll", SetLastError=true)] |
||||
static extern public int recv(IntPtr socket, byte[] buff, int len, int flags); |
||||
|
||||
[DllImport("ws2_32.Dll", SetLastError=true)] |
||||
static extern public int send(IntPtr socket, byte[] buff, int len, int flags); |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
} |
@ -0,0 +1,64 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
internal class Platform |
||||
{ |
||||
private static bool inited; |
||||
private static bool isMono; |
||||
|
||||
/// <summary> |
||||
/// By creating a private ctor, we keep the compiler from creating a default ctor |
||||
/// </summary> |
||||
private Platform() |
||||
{ |
||||
} |
||||
|
||||
public static bool IsWindows() |
||||
{ |
||||
OperatingSystem os = Environment.OSVersion; |
||||
switch (os.Platform) |
||||
{ |
||||
case PlatformID.Win32NT: |
||||
case PlatformID.Win32S: |
||||
case PlatformID.Win32Windows: |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public static bool IsMono() |
||||
{ |
||||
if (!inited) |
||||
Init(); |
||||
return isMono; |
||||
} |
||||
|
||||
private static void Init() |
||||
{ |
||||
inited = true; |
||||
Type t = Type.GetType("Mono.Runtime"); |
||||
isMono = t != null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,275 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
class SHA1Hash |
||||
{ |
||||
private const int SHA1_HASH_SIZE = 20; // Hash size in bytes |
||||
|
||||
// Constants defined in SHA-1 |
||||
private static uint[] K = new uint[4] { |
||||
0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; |
||||
|
||||
private static uint[] sha_const_key = new uint[5] { |
||||
0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; |
||||
|
||||
private ulong length; // Message length in bits |
||||
private uint[] intermediateHash; // Message Digest |
||||
private bool computed; // Is the digest computed? |
||||
// private bool corrupted; // Is the message digest corrupted? |
||||
private short messageBlockIndex; // Index into message block array |
||||
private byte[] messageBlock; // 512-bit message blocks |
||||
|
||||
public SHA1Hash() |
||||
{ |
||||
intermediateHash = new uint[SHA1_HASH_SIZE/4]; |
||||
messageBlock = new byte[64]; |
||||
Reset(); |
||||
} |
||||
|
||||
public void Reset() |
||||
{ |
||||
/*#ifndef DBUG_OFF |
||||
if (!context) |
||||
return SHA_NULL; |
||||
#endif*/ |
||||
|
||||
length = 0; |
||||
messageBlockIndex = 0; |
||||
|
||||
intermediateHash[0] = sha_const_key[0]; |
||||
intermediateHash[1] = sha_const_key[1]; |
||||
intermediateHash[2] = sha_const_key[2]; |
||||
intermediateHash[3] = sha_const_key[3]; |
||||
intermediateHash[4] = sha_const_key[4]; |
||||
|
||||
computed = false; |
||||
// corrupted = false; |
||||
} |
||||
|
||||
public byte[] ComputeHash(byte[] buffer) |
||||
{ |
||||
Reset(); |
||||
Input(buffer, 0, buffer.Length); |
||||
return Result(); |
||||
} |
||||
|
||||
public void Input(byte[] buffer, int index, int bufLen) |
||||
{ |
||||
if (buffer == null || bufLen == 0) return; |
||||
|
||||
if (index < 0 || index > buffer.Length - 1) |
||||
throw new ArgumentException("Index must be a value between 0 and buffer.Length-1", "index"); |
||||
if (bufLen < 0) |
||||
throw new ArgumentException("Length must be a value > 0", "length"); |
||||
if ((bufLen+index) > buffer.Length) |
||||
throw new ArgumentException("Length + index would extend past the end of buffer", "length"); |
||||
|
||||
/*#ifndef DBUG_OFF |
||||
// We assume client konows what it is doing in non-debug mode |
||||
if (!context || !message_array) |
||||
return SHA_NULL; |
||||
if (context->Computed) |
||||
return (context->Corrupted= SHA_STATE_ERROR); |
||||
if (context->Corrupted) |
||||
return context->Corrupted; |
||||
#endif*/ |
||||
|
||||
while (bufLen-- > 0) |
||||
{ |
||||
messageBlock[messageBlockIndex++] = (byte)(buffer[index++] & 0xFF); |
||||
length += 8; /* Length is in bits */ |
||||
|
||||
/*#ifndef DBUG_OFF |
||||
|
||||
// Then we're not debugging we assume we never will get message longer |
||||
//2^64 bits. |
||||
|
||||
if (context->Length == 0) |
||||
return (context->Corrupted= 1); // Message is too long |
||||
#endif*/ |
||||
|
||||
if (messageBlockIndex == 64) |
||||
ProcessMessageBlock(); |
||||
} |
||||
} |
||||
|
||||
private void ProcessMessageBlock() |
||||
{ |
||||
uint temp; // Temporary word value |
||||
uint[] W; // Word sequence |
||||
uint A, B, C, D, E; // Word buffers |
||||
|
||||
W = new uint[80]; |
||||
|
||||
//Initialize the first 16 words in the array W |
||||
for (int t = 0; t < 16; t++) |
||||
{ |
||||
int index=t*4; |
||||
W[t] = (uint)messageBlock[index] << 24; |
||||
W[t] |= (uint)messageBlock[index + 1] << 16; |
||||
W[t] |= (uint)messageBlock[index + 2] << 8; |
||||
W[t] |= (uint)messageBlock[index + 3]; |
||||
} |
||||
|
||||
|
||||
for (int t = 16; t < 80; t++) |
||||
{ |
||||
W[t] = CircularShift(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); |
||||
} |
||||
|
||||
A = intermediateHash[0]; |
||||
B = intermediateHash[1]; |
||||
C = intermediateHash[2]; |
||||
D = intermediateHash[3]; |
||||
E = intermediateHash[4]; |
||||
|
||||
for (int t = 0; t < 20; t++) |
||||
{ |
||||
temp= CircularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; |
||||
E = D; |
||||
D = C; |
||||
C = CircularShift(30, B); |
||||
B = A; |
||||
A = temp; |
||||
} |
||||
|
||||
for (int t = 20; t < 40; t++) |
||||
{ |
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; |
||||
E = D; |
||||
D = C; |
||||
C = CircularShift(30,B); |
||||
B = A; |
||||
A = temp; |
||||
} |
||||
|
||||
for (int t = 40; t < 60; t++) |
||||
{ |
||||
temp= (CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]); |
||||
E = D; |
||||
D = C; |
||||
C = CircularShift(30,B); |
||||
B = A; |
||||
A = temp; |
||||
} |
||||
|
||||
for (int t = 60; t < 80; t++) |
||||
{ |
||||
temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; |
||||
E = D; |
||||
D = C; |
||||
C = CircularShift(30,B); |
||||
B = A; |
||||
A = temp; |
||||
} |
||||
|
||||
intermediateHash[0] += A; |
||||
intermediateHash[1] += B; |
||||
intermediateHash[2] += C; |
||||
intermediateHash[3] += D; |
||||
intermediateHash[4] += E; |
||||
|
||||
messageBlockIndex = 0; |
||||
} |
||||
|
||||
private static uint CircularShift(int bits, uint word) |
||||
{ |
||||
return (((word) << (bits)) | ((word) >> (32-(bits)))); |
||||
} |
||||
|
||||
private void PadMessage() |
||||
{ |
||||
/* |
||||
Check to see if the current message block is too small to hold |
||||
the initial padding bits and length. If so, we will pad the |
||||
block, process it, and then continue padding into a second |
||||
block. |
||||
*/ |
||||
|
||||
int i = messageBlockIndex; |
||||
|
||||
if (i > 55) |
||||
{ |
||||
messageBlock[i++] = 0x80; |
||||
Array.Clear(messageBlock, i, 64-i); |
||||
//bzero((char*) &context->Message_Block[i], sizeof(messageBlock[0])*(64-i)); |
||||
messageBlockIndex = 64; |
||||
|
||||
/* This function sets messageBlockIndex to zero */ |
||||
ProcessMessageBlock(); |
||||
|
||||
Array.Clear(messageBlock, 0, 56); |
||||
//bzero((char*) &context->Message_Block[0], sizeof(messageBlock[0])*56); |
||||
messageBlockIndex = 56; |
||||
} |
||||
else |
||||
{ |
||||
messageBlock[i++] = 0x80; |
||||
Array.Clear(messageBlock, i, 56-i); |
||||
//bzero((char*) &messageBlock[i], sizeof(messageBlock[0])*(56-i)); |
||||
messageBlockIndex = 56; |
||||
} |
||||
|
||||
// Store the message length as the last 8 octets |
||||
messageBlock[56] = (byte)(length >> 56); |
||||
messageBlock[57] = (byte)(length >> 48); |
||||
messageBlock[58] = (byte)(length >> 40); |
||||
messageBlock[59] = (byte)(length >> 32); |
||||
messageBlock[60] = (byte)(length >> 24); |
||||
messageBlock[61] = (byte)(length >> 16); |
||||
messageBlock[62] = (byte)(length >> 8); |
||||
messageBlock[63] = (byte)length; |
||||
|
||||
ProcessMessageBlock(); |
||||
} |
||||
|
||||
public byte[] Result() |
||||
{ |
||||
/*#ifndef DBUG_OFF |
||||
if (!context || !Message_Digest) |
||||
return SHA_NULL; |
||||
|
||||
if (context->Corrupted) |
||||
return context->Corrupted; |
||||
#endif*/ |
||||
|
||||
if (!computed) |
||||
{ |
||||
PadMessage(); |
||||
|
||||
// message may be sensitive, clear it out |
||||
Array.Clear(messageBlock, 0, 64); |
||||
//bzero((char*) messageBlock,64); |
||||
length = 0; /* and clear length */ |
||||
computed = true; |
||||
} |
||||
|
||||
byte[] messageDigest = new byte[SHA1_HASH_SIZE]; |
||||
for (int i = 0; i < SHA1_HASH_SIZE; i++) |
||||
messageDigest[i] = (byte)((intermediateHash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ))); |
||||
return messageDigest; |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,353 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Runtime.InteropServices; |
||||
using System.Threading; |
||||
using System.IO; |
||||
using MySql.Data.MySqlClient; |
||||
using System.Diagnostics; |
||||
|
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
#if !PocketPC |
||||
|
||||
/// <summary> |
||||
/// Helper class to encapsulate shared memory functionality |
||||
/// Also cares of proper cleanup of file mapping object and cew |
||||
/// </summary> |
||||
internal class SharedMemory : IDisposable |
||||
{ |
||||
private const uint FILE_MAP_WRITE = 0x0002; |
||||
|
||||
IntPtr fileMapping; |
||||
IntPtr view; |
||||
|
||||
public SharedMemory(string name, IntPtr size) |
||||
{ |
||||
fileMapping = NativeMethods.OpenFileMapping(FILE_MAP_WRITE, false, |
||||
name); |
||||
if (fileMapping == IntPtr.Zero) |
||||
{ |
||||
throw new MySqlException("Cannot open file mapping " + name); |
||||
} |
||||
view = NativeMethods.MapViewOfFile(fileMapping, FILE_MAP_WRITE, 0, 0, size); |
||||
} |
||||
|
||||
public IntPtr View |
||||
{ |
||||
get { return view; } |
||||
} |
||||
|
||||
public void Dispose() |
||||
{ |
||||
Dispose(true); |
||||
GC.SuppressFinalize(this); |
||||
} |
||||
|
||||
|
||||
protected virtual void Dispose(bool disposing) |
||||
{ |
||||
if (disposing) |
||||
{ |
||||
if (view != IntPtr.Zero) |
||||
{ |
||||
NativeMethods.UnmapViewOfFile(view); |
||||
view = IntPtr.Zero; |
||||
} |
||||
if (fileMapping != IntPtr.Zero) |
||||
{ |
||||
// Free the handle |
||||
NativeMethods.CloseHandle(fileMapping); |
||||
fileMapping = IntPtr.Zero; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
/// <summary> |
||||
/// Summary description for SharedMemoryStream. |
||||
/// </summary> |
||||
internal class SharedMemoryStream : Stream |
||||
{ |
||||
private string memoryName; |
||||
private EventWaitHandle serverRead; |
||||
private EventWaitHandle serverWrote; |
||||
private EventWaitHandle clientRead; |
||||
private EventWaitHandle clientWrote; |
||||
private EventWaitHandle connectionClosed; |
||||
private SharedMemory data; |
||||
private int bytesLeft; |
||||
private int position; |
||||
private int connectNumber; |
||||
|
||||
private const int BUFFERLENGTH = 16004; |
||||
|
||||
private int readTimeout = System.Threading.Timeout.Infinite; |
||||
private int writeTimeout = System.Threading.Timeout.Infinite; |
||||
|
||||
public SharedMemoryStream(string memName) |
||||
{ |
||||
memoryName = memName; |
||||
} |
||||
|
||||
public void Open(uint timeOut) |
||||
{ |
||||
if (connectionClosed != null) |
||||
{ |
||||
Debug.Assert(false, "Connection is already open"); |
||||
} |
||||
GetConnectNumber(timeOut); |
||||
SetupEvents(); |
||||
} |
||||
|
||||
public override void Close() |
||||
{ |
||||
if (connectionClosed != null) |
||||
{ |
||||
bool isClosed = connectionClosed.WaitOne(0); |
||||
if (!isClosed) |
||||
{ |
||||
connectionClosed.Set(); |
||||
connectionClosed.Close(); |
||||
} |
||||
connectionClosed = null; |
||||
EventWaitHandle[] handles = |
||||
{serverRead, serverWrote, clientRead, clientWrote}; |
||||
|
||||
for(int i=0; i< handles.Length; i++) |
||||
{ |
||||
if(handles[i] != null) |
||||
handles[i].Close(); |
||||
} |
||||
if (data != null) |
||||
{ |
||||
data.Dispose(); |
||||
data = null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void GetConnectNumber(uint timeOut) |
||||
{ |
||||
EventWaitHandle connectRequest; |
||||
try |
||||
{ |
||||
connectRequest = |
||||
EventWaitHandle.OpenExisting(memoryName + "_CONNECT_REQUEST"); |
||||
|
||||
} |
||||
catch (Exception) |
||||
{ |
||||
// If server runs as service, its shared memory is global |
||||
// And if connector runs in user session, it needs to prefix |
||||
// shared memory name with "Global\" |
||||
string prefixedMemoryName = @"Global\" + memoryName; |
||||
connectRequest = |
||||
EventWaitHandle.OpenExisting(prefixedMemoryName + "_CONNECT_REQUEST"); |
||||
memoryName = prefixedMemoryName; |
||||
} |
||||
EventWaitHandle connectAnswer = |
||||
EventWaitHandle.OpenExisting(memoryName + "_CONNECT_ANSWER"); |
||||
using (SharedMemory connectData = |
||||
new SharedMemory(memoryName + "_CONNECT_DATA", (IntPtr)4)) |
||||
{ |
||||
// now start the connection |
||||
if (!connectRequest.Set()) |
||||
throw new MySqlException("Failed to open shared memory connection"); |
||||
if (!connectAnswer.WaitOne((int)(timeOut * 1000), false)) |
||||
throw new MySqlException("Timeout during connection"); |
||||
connectNumber = Marshal.ReadInt32(connectData.View); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void SetupEvents() |
||||
{ |
||||
string prefix = memoryName + "_" + connectNumber; |
||||
data = new SharedMemory(prefix + "_DATA", (IntPtr)BUFFERLENGTH); |
||||
serverWrote = EventWaitHandle.OpenExisting(prefix + "_SERVER_WROTE"); |
||||
serverRead = EventWaitHandle.OpenExisting(prefix + "_SERVER_READ"); |
||||
clientWrote = EventWaitHandle.OpenExisting(prefix + "_CLIENT_WROTE"); |
||||
clientRead = EventWaitHandle.OpenExisting(prefix + "_CLIENT_READ"); |
||||
connectionClosed = EventWaitHandle.OpenExisting(prefix + "_CONNECTION_CLOSED"); |
||||
|
||||
// tell the server we are ready |
||||
serverRead.Set(); |
||||
} |
||||
|
||||
#region Properties |
||||
public override bool CanRead |
||||
{ |
||||
get { return true; } |
||||
} |
||||
|
||||
public override bool CanSeek |
||||
{ |
||||
get { return false; } |
||||
} |
||||
|
||||
public override bool CanWrite |
||||
{ |
||||
get { return true; } |
||||
} |
||||
|
||||
public override long Length |
||||
{ |
||||
get { throw new NotSupportedException("SharedMemoryStream does not support seeking - length"); } |
||||
} |
||||
|
||||
public override long Position |
||||
{ |
||||
get { throw new NotSupportedException("SharedMemoryStream does not support seeking - position"); } |
||||
set { } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
public override void Flush() |
||||
{ |
||||
// No need to flush anything to disk ,as our shared memory is backed |
||||
// by the page file |
||||
} |
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) |
||||
{ |
||||
int timeLeft = readTimeout; |
||||
WaitHandle[] waitHandles = { serverWrote, connectionClosed }; |
||||
LowResolutionStopwatch stopwatch = new LowResolutionStopwatch(); |
||||
while (bytesLeft == 0) |
||||
{ |
||||
stopwatch.Start(); |
||||
int index = WaitHandle.WaitAny(waitHandles, timeLeft); |
||||
stopwatch.Stop(); |
||||
if (index == WaitHandle.WaitTimeout) |
||||
throw new TimeoutException("Timeout when reading from shared memory"); |
||||
|
||||
if (waitHandles[index] == connectionClosed) |
||||
throw new MySqlException("Connection to server lost",true, null); |
||||
|
||||
if (readTimeout != System.Threading.Timeout.Infinite) |
||||
{ |
||||
timeLeft = readTimeout - (int)stopwatch.ElapsedMilliseconds; |
||||
if (timeLeft < 0) |
||||
throw new TimeoutException("Timeout when reading from shared memory"); |
||||
} |
||||
|
||||
bytesLeft = Marshal.ReadInt32(data.View); |
||||
position = 4; |
||||
} |
||||
|
||||
int len = Math.Min(count, bytesLeft); |
||||
long baseMem = data.View.ToInt64() + position; |
||||
|
||||
for (int i = 0; i < len; i++, position++) |
||||
buffer[offset + i] = Marshal.ReadByte((IntPtr)(baseMem + i)); |
||||
|
||||
bytesLeft -= len; |
||||
if (bytesLeft == 0) |
||||
clientRead.Set(); |
||||
|
||||
return len; |
||||
} |
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) |
||||
{ |
||||
throw new NotSupportedException("SharedMemoryStream does not support seeking"); |
||||
} |
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) |
||||
{ |
||||
int leftToDo = count; |
||||
int buffPos = offset; |
||||
WaitHandle[] waitHandles = { serverRead, connectionClosed }; |
||||
LowResolutionStopwatch stopwatch = new LowResolutionStopwatch(); |
||||
int timeLeft = writeTimeout; |
||||
|
||||
while (leftToDo > 0) |
||||
{ |
||||
stopwatch.Start(); |
||||
int index = WaitHandle.WaitAny(waitHandles, timeLeft); |
||||
stopwatch.Stop(); |
||||
|
||||
if (waitHandles[index] == connectionClosed) |
||||
throw new MySqlException("Connection to server lost",true, null); |
||||
|
||||
if (index == WaitHandle.WaitTimeout) |
||||
throw new TimeoutException("Timeout when reading from shared memory"); |
||||
|
||||
if (writeTimeout != System.Threading.Timeout.Infinite) |
||||
{ |
||||
timeLeft = writeTimeout - (int)stopwatch.ElapsedMilliseconds; |
||||
if (timeLeft < 0) |
||||
throw new TimeoutException("Timeout when writing to shared memory"); |
||||
} |
||||
int bytesToDo = Math.Min(leftToDo, BUFFERLENGTH); |
||||
long baseMem = data.View.ToInt64() + 4; |
||||
Marshal.WriteInt32(data.View, bytesToDo); |
||||
Marshal.Copy(buffer, buffPos, (IntPtr)baseMem, bytesToDo); |
||||
buffPos += bytesToDo; |
||||
leftToDo -= bytesToDo; |
||||
if (!clientWrote.Set()) |
||||
throw new MySqlException("Writing to shared memory failed"); |
||||
} |
||||
} |
||||
|
||||
public override void SetLength(long value) |
||||
{ |
||||
throw new NotSupportedException("SharedMemoryStream does not support seeking"); |
||||
} |
||||
|
||||
public override bool CanTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
public override int ReadTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return readTimeout; |
||||
} |
||||
set |
||||
{ |
||||
readTimeout = value; |
||||
} |
||||
} |
||||
|
||||
public override int WriteTimeout |
||||
{ |
||||
get |
||||
{ |
||||
return writeTimeout; |
||||
} |
||||
set |
||||
{ |
||||
writeTimeout = value; |
||||
} |
||||
} |
||||
|
||||
} |
||||
#endif |
||||
} |
@ -0,0 +1,142 @@ |
||||
// Copyright (c) 2004-2007 MySQL AB |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.IO; |
||||
using System.Net; |
||||
using System.Net.Sockets; |
||||
using System.Collections; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for MySqlSocket. |
||||
/// </summary> |
||||
internal sealed class SocketStream : Stream |
||||
{ |
||||
private Socket socket; |
||||
|
||||
public SocketStream(AddressFamily addressFamily, SocketType socketType, ProtocolType protocol) |
||||
{ |
||||
socket = new Socket(addressFamily, socketType, protocol); |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
public Socket Socket |
||||
{ |
||||
get { return socket; } |
||||
} |
||||
|
||||
public override bool CanRead |
||||
{ |
||||
get { return true; } |
||||
} |
||||
|
||||
public override bool CanSeek |
||||
{ |
||||
get { return false; } |
||||
} |
||||
|
||||
public override bool CanWrite |
||||
{ |
||||
get { return true; } |
||||
} |
||||
|
||||
public override long Length |
||||
{ |
||||
get { return 0; } |
||||
} |
||||
|
||||
public override long Position |
||||
{ |
||||
get { return 0; } |
||||
set { throw new NotSupportedException("SocketStream does not support seek"); } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Stream Implementation |
||||
|
||||
public override void Flush() |
||||
{ |
||||
} |
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) |
||||
{ |
||||
return socket.Receive(buffer, offset, count, SocketFlags.None); |
||||
} |
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) |
||||
{ |
||||
throw new NotSupportedException("SocketStream does not support seek"); |
||||
} |
||||
|
||||
public override void SetLength(long value) |
||||
{ |
||||
} |
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) |
||||
{ |
||||
socket.Send(buffer, offset, count, SocketFlags.None); |
||||
} |
||||
|
||||
|
||||
#endregion |
||||
|
||||
public bool Connect(EndPoint remoteEP, int timeout) |
||||
{ |
||||
// set the socket to non blocking |
||||
socket.Blocking = false; |
||||
|
||||
// then we star the connect |
||||
SocketAddress addr = remoteEP.Serialize(); |
||||
byte[] buff = new byte[addr.Size]; |
||||
for (int i=0; i<addr.Size; i++) |
||||
buff[i] = addr[i]; |
||||
|
||||
NativeMethods.connect(socket.Handle, buff, addr.Size); |
||||
int wsaerror = NativeMethods.WSAGetLastError(); |
||||
if (wsaerror != 10035) |
||||
{ |
||||
// this is probably an IPV6 address |
||||
if (wsaerror == 10047) |
||||
return false; |
||||
throw new SocketException(wsaerror); |
||||
} |
||||
|
||||
// next we wait for our connect timeout or until the socket is connected |
||||
ArrayList write = new ArrayList(); |
||||
write.Add(socket); |
||||
ArrayList error = new ArrayList(); |
||||
error.Add(socket); |
||||
|
||||
Socket.Select(null, write, error, timeout*1000*1000); |
||||
|
||||
if (write.Count == 0) return false; |
||||
|
||||
// set socket back to blocking mode |
||||
socket.Blocking = true; |
||||
return true; |
||||
} |
||||
|
||||
|
||||
} |
||||
} |
@ -0,0 +1,264 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.IO; |
||||
using System.Net; |
||||
using System.Net.Sockets; |
||||
using System.Reflection; |
||||
using System.Diagnostics; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
using System.Runtime.InteropServices; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for StreamCreator. |
||||
/// </summary> |
||||
internal class StreamCreator |
||||
{ |
||||
string hostList; |
||||
uint port; |
||||
string pipeName; |
||||
uint timeOut; |
||||
uint keepalive; |
||||
|
||||
public StreamCreator(string hosts, uint port, string pipeName, uint keepalive) |
||||
{ |
||||
hostList = hosts; |
||||
if (hostList == null || hostList.Length == 0) |
||||
hostList = "localhost"; |
||||
this.port = port; |
||||
this.pipeName = pipeName; |
||||
this.keepalive = keepalive; |
||||
} |
||||
|
||||
public Stream GetStream(uint timeout) |
||||
{ |
||||
timeOut = timeout; |
||||
|
||||
if (hostList.StartsWith("/", StringComparison.OrdinalIgnoreCase)) |
||||
return CreateSocketStream(null, true); |
||||
|
||||
string[] dnsHosts = hostList.Split('&'); |
||||
|
||||
Random random = new Random((int)DateTime.Now.Ticks); |
||||
int index = random.Next(dnsHosts.Length); |
||||
int pos = 0; |
||||
bool usePipe = (pipeName != null && pipeName.Length != 0); |
||||
Stream stream = null; |
||||
|
||||
while (pos < dnsHosts.Length) |
||||
{ |
||||
try |
||||
{ |
||||
if (usePipe) |
||||
{ |
||||
#if !CF |
||||
stream = NamedPipeStream.Create(pipeName, dnsHosts[index], timeout); |
||||
#endif |
||||
} |
||||
else |
||||
{ |
||||
IPHostEntry ipHE = GetHostEntry(dnsHosts[index]); |
||||
foreach (IPAddress address in ipHE.AddressList) |
||||
{ |
||||
// MySQL doesn't currently support IPv6 addresses |
||||
if (address.AddressFamily == AddressFamily.InterNetworkV6) |
||||
continue; |
||||
stream = CreateSocketStream(address, false); |
||||
if (stream != null) break; |
||||
} |
||||
} |
||||
if (stream != null) |
||||
break; |
||||
index++; |
||||
if (index == dnsHosts.Length) |
||||
index = 0; |
||||
pos++; |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
// if on last host then throw |
||||
if (pos >= dnsHosts.Length - 1) throw; |
||||
// else continue |
||||
} |
||||
} |
||||
|
||||
return stream; |
||||
} |
||||
|
||||
private IPHostEntry ParseIPAddress(string hostname) |
||||
{ |
||||
IPHostEntry ipHE = null; |
||||
#if !CF |
||||
IPAddress addr; |
||||
if (IPAddress.TryParse(hostname, out addr)) |
||||
{ |
||||
ipHE = new IPHostEntry(); |
||||
ipHE.AddressList = new IPAddress[1]; |
||||
ipHE.AddressList[0] = addr; |
||||
} |
||||
#endif |
||||
return ipHE; |
||||
} |
||||
|
||||
#if CF |
||||
IPHostEntry GetDnsHostEntry(string hostname) |
||||
{ |
||||
return Dns.GetHostEntry(hostname); |
||||
} |
||||
#else |
||||
IPHostEntry GetDnsHostEntry(string hostname) |
||||
{ |
||||
LowResolutionStopwatch stopwatch = new LowResolutionStopwatch(); |
||||
|
||||
try |
||||
{ |
||||
stopwatch.Start(); |
||||
return Dns.GetHostEntry(hostname); |
||||
} |
||||
catch (SocketException ex) |
||||
{ |
||||
string message = String.Format(Resources.GetHostEntryFailed, |
||||
stopwatch.Elapsed, hostname, ex.SocketErrorCode, |
||||
ex.ErrorCode, ex.NativeErrorCode); |
||||
throw new Exception(message, ex); |
||||
} |
||||
finally |
||||
{ |
||||
stopwatch.Stop(); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
private IPHostEntry GetHostEntry(string hostname) |
||||
{ |
||||
IPHostEntry ipHE = ParseIPAddress(hostname); |
||||
if (ipHE != null) return ipHE; |
||||
return GetDnsHostEntry(hostname); |
||||
} |
||||
|
||||
#if !CF |
||||
|
||||
private static EndPoint CreateUnixEndPoint(string host) |
||||
{ |
||||
// first we need to load the Mono.posix assembly |
||||
Assembly a = Assembly.Load("Mono.Posix"); |
||||
|
||||
// then we need to construct a UnixEndPoint object |
||||
EndPoint ep = (EndPoint)a.CreateInstance("Mono.Posix.UnixEndPoint", |
||||
false, BindingFlags.CreateInstance, null, |
||||
new object[1] { host }, null, null); |
||||
return ep; |
||||
} |
||||
#endif |
||||
|
||||
private Stream CreateSocketStream(IPAddress ip, bool unix) |
||||
{ |
||||
EndPoint endPoint; |
||||
#if !CF |
||||
if (!Platform.IsWindows() && unix) |
||||
endPoint = CreateUnixEndPoint(hostList); |
||||
else |
||||
#endif |
||||
endPoint = new IPEndPoint(ip, (int)port); |
||||
|
||||
Socket socket = unix ? |
||||
new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP) : |
||||
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
||||
if (keepalive > 0) |
||||
{ |
||||
SetKeepAlive(socket, keepalive); |
||||
} |
||||
IAsyncResult ias = socket.BeginConnect(endPoint, null, null); |
||||
if (!ias.AsyncWaitHandle.WaitOne((int)timeOut * 1000, false)) |
||||
{ |
||||
socket.Close(); |
||||
return null; |
||||
} |
||||
try |
||||
{ |
||||
socket.EndConnect(ias); |
||||
} |
||||
catch (Exception) |
||||
{ |
||||
socket.Close(); |
||||
throw; |
||||
} |
||||
MyNetworkStream stream = new MyNetworkStream(socket, true); |
||||
GC.SuppressFinalize(socket); |
||||
GC.SuppressFinalize(stream); |
||||
return stream; |
||||
} |
||||
|
||||
|
||||
|
||||
/// <summary> |
||||
/// Set keepalive + timeout on socket. |
||||
/// </summary> |
||||
/// <param name="s">socket</param> |
||||
/// <param name="time">keepalive timeout, in seconds</param> |
||||
private static void SetKeepAlive(Socket s, uint time) |
||||
{ |
||||
|
||||
#if !CF |
||||
uint on = 1; |
||||
uint interval = 1000; // default interval = 1 sec |
||||
|
||||
uint timeMilliseconds; |
||||
if (time > UInt32.MaxValue / 1000) |
||||
timeMilliseconds = UInt32.MaxValue; |
||||
else |
||||
timeMilliseconds = time * 1000; |
||||
|
||||
// Use Socket.IOControl to implement equivalent of |
||||
// WSAIoctl with SOL_KEEPALIVE_VALS |
||||
|
||||
// the native structure passed to WSAIoctl is |
||||
//struct tcp_keepalive { |
||||
// ULONG onoff; |
||||
// ULONG keepalivetime; |
||||
// ULONG keepaliveinterval; |
||||
//}; |
||||
// marshal the equivalent of the native structure into a byte array |
||||
|
||||
byte[] inOptionValues = new byte[12]; |
||||
BitConverter.GetBytes(on).CopyTo(inOptionValues, 0); |
||||
BitConverter.GetBytes(time).CopyTo(inOptionValues, 4); |
||||
BitConverter.GetBytes(interval).CopyTo(inOptionValues, 8); |
||||
try |
||||
{ |
||||
// call WSAIoctl via IOControl |
||||
s.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null); |
||||
return; |
||||
} |
||||
catch (NotImplementedException) |
||||
{ |
||||
// Mono throws not implemented currently |
||||
} |
||||
#endif |
||||
// Fallback if Socket.IOControl is not available ( Compact Framework ) |
||||
// or not implemented ( Mono ). Keepalive option will still be set, but |
||||
// with timeout is kept default. |
||||
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,100 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using MySql.Data.MySqlClient; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.Common |
||||
{ |
||||
/// <summary> |
||||
/// Summary description for Version. |
||||
/// </summary> |
||||
internal struct DBVersion |
||||
{ |
||||
private int major; |
||||
private int minor; |
||||
private int build; |
||||
private string srcString; |
||||
|
||||
public DBVersion( string s, int major, int minor, int build) |
||||
{ |
||||
this.major = major; |
||||
this.minor = minor; |
||||
this.build = build; |
||||
srcString = s; |
||||
} |
||||
|
||||
public int Major |
||||
{ |
||||
get { return major; } |
||||
} |
||||
|
||||
public int Minor |
||||
{ |
||||
get { return minor; } |
||||
} |
||||
|
||||
public int Build |
||||
{ |
||||
get { return build; } |
||||
} |
||||
|
||||
public static DBVersion Parse( string versionString ) |
||||
{ |
||||
int start = 0; |
||||
int index = versionString.IndexOf('.', start); |
||||
if (index == -1) |
||||
throw new MySqlException(Resources.BadVersionFormat); |
||||
string val = versionString.Substring(start, index-start).Trim(); |
||||
int major = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); |
||||
|
||||
start = index+1; |
||||
index = versionString.IndexOf('.', start); |
||||
if (index == -1) |
||||
throw new MySqlException(Resources.BadVersionFormat); |
||||
val = versionString.Substring(start, index-start).Trim(); |
||||
int minor = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); |
||||
|
||||
start = index+1; |
||||
int i = start; |
||||
while (i < versionString.Length && Char.IsDigit(versionString, i)) |
||||
i++; |
||||
val = versionString.Substring(start, i-start).Trim(); |
||||
int build = Convert.ToInt32(val, System.Globalization.NumberFormatInfo.InvariantInfo); |
||||
|
||||
return new DBVersion(versionString, major, minor, build); |
||||
} |
||||
|
||||
public bool isAtLeast(int majorNum, int minorNum, int buildNum) |
||||
{ |
||||
if (major > majorNum) return true; |
||||
if (major == majorNum && minor > minorNum) return true; |
||||
if (major == majorNum && minor == minorNum && build >= buildNum) return true; |
||||
return false; |
||||
} |
||||
|
||||
public override string ToString() |
||||
{ |
||||
return srcString; |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,309 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.Data.Common; |
||||
using System.ComponentModel; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/class/*'/> |
||||
#if !CF |
||||
[System.Drawing.ToolboxBitmap( typeof(MySqlDataAdapter), "MySqlClient.resources.dataadapter.bmp")] |
||||
[System.ComponentModel.DesignerCategory("Code")] |
||||
[Designer("MySql.Data.MySqlClient.Design.MySqlDataAdapterDesigner,MySqlClient.Design")] |
||||
#endif |
||||
public sealed class MySqlDataAdapter : DbDataAdapter, IDbDataAdapter, IDataAdapter, ICloneable |
||||
{ |
||||
private bool loadingDefaults; |
||||
private int updateBatchSize; |
||||
List<IDbCommand> commandBatch; |
||||
|
||||
/// <summary> |
||||
/// Occurs during Update before a command is executed against the data source. The attempt to update is made, so the event fires. |
||||
/// </summary> |
||||
public event MySqlRowUpdatingEventHandler RowUpdating; |
||||
|
||||
/// <summary> |
||||
/// Occurs during Update after a command is executed against the data source. The attempt to update is made, so the event fires. |
||||
/// </summary> |
||||
public event MySqlRowUpdatedEventHandler RowUpdated; |
||||
|
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/Ctor/*'/> |
||||
public MySqlDataAdapter() |
||||
{ |
||||
loadingDefaults = true; |
||||
updateBatchSize = 1; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/Ctor1/*'/> |
||||
public MySqlDataAdapter(MySqlCommand selectCommand) : this() |
||||
{ |
||||
SelectCommand = selectCommand; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/Ctor2/*'/> |
||||
public MySqlDataAdapter(string selectCommandText, MySqlConnection connection) : this() |
||||
{ |
||||
SelectCommand = new MySqlCommand(selectCommandText, connection); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/Ctor3/*'/> |
||||
public MySqlDataAdapter(string selectCommandText, string selectConnString) : this() |
||||
{ |
||||
SelectCommand = new MySqlCommand(selectCommandText, |
||||
new MySqlConnection(selectConnString) ); |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/DeleteCommand/*'/> |
||||
#if !CF |
||||
[Description("Used during Update for deleted rows in Dataset.")] |
||||
#endif |
||||
public new MySqlCommand DeleteCommand |
||||
{ |
||||
get { return (MySqlCommand)base.DeleteCommand; } |
||||
set { base.DeleteCommand = value; } |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/InsertCommand/*'/> |
||||
#if !CF |
||||
[Description("Used during Update for new rows in Dataset.")] |
||||
#endif |
||||
public new MySqlCommand InsertCommand |
||||
{ |
||||
get { return (MySqlCommand)base.InsertCommand; } |
||||
set { base.InsertCommand = value; } |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/SelectCommand/*'/> |
||||
#if !CF |
||||
[Description("Used during Fill/FillSchema")] |
||||
[Category("Fill")] |
||||
#endif |
||||
public new MySqlCommand SelectCommand |
||||
{ |
||||
get { return (MySqlCommand)base.SelectCommand; } |
||||
set { base.SelectCommand = value; } |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataAdapter.xml' path='docs/UpdateCommand/*'/> |
||||
#if !CF |
||||
[Description("Used during Update for modified rows in Dataset.")] |
||||
#endif |
||||
public new MySqlCommand UpdateCommand |
||||
{ |
||||
get { return (MySqlCommand)base.UpdateCommand; } |
||||
set { base.UpdateCommand = value; } |
||||
} |
||||
|
||||
internal bool LoadDefaults |
||||
{ |
||||
get { return loadingDefaults; } |
||||
set { loadingDefaults = value; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
#region Batching Support |
||||
|
||||
public override int UpdateBatchSize |
||||
{ |
||||
get { return updateBatchSize; } |
||||
set { updateBatchSize = value; } |
||||
} |
||||
|
||||
protected override void InitializeBatching() |
||||
{ |
||||
commandBatch = new List<IDbCommand>(); |
||||
} |
||||
|
||||
protected override int AddToBatch(IDbCommand command) |
||||
{ |
||||
// the first time each command is asked to be batched, we ask |
||||
// that command to prepare its batchable command text. We only want |
||||
// to do this one time for each command |
||||
MySqlCommand commandToBatch = (MySqlCommand)command; |
||||
if (commandToBatch.BatchableCommandText == null) |
||||
commandToBatch.GetCommandTextForBatching(); |
||||
|
||||
IDbCommand cloneCommand = (IDbCommand)((ICloneable)command).Clone(); |
||||
commandBatch.Add(cloneCommand); |
||||
|
||||
return commandBatch.Count - 1; |
||||
} |
||||
|
||||
protected override int ExecuteBatch() |
||||
{ |
||||
int recordsAffected = 0; |
||||
int index = 0; |
||||
while (index < commandBatch.Count) |
||||
{ |
||||
MySqlCommand cmd = (MySqlCommand)commandBatch[index++]; |
||||
for (int index2 = index; index2 < commandBatch.Count; index2++,index++) |
||||
{ |
||||
MySqlCommand cmd2 = (MySqlCommand)commandBatch[index2]; |
||||
if (cmd2.BatchableCommandText == null || |
||||
cmd2.CommandText != cmd.CommandText) break; |
||||
cmd.AddToBatch(cmd2); |
||||
} |
||||
recordsAffected += cmd.ExecuteNonQuery(); |
||||
} |
||||
return recordsAffected; |
||||
} |
||||
|
||||
protected override void ClearBatch() |
||||
{ |
||||
if (commandBatch.Count > 0) |
||||
{ |
||||
MySqlCommand cmd = (MySqlCommand)commandBatch[0]; |
||||
if (cmd.Batch != null) |
||||
cmd.Batch.Clear(); |
||||
} |
||||
commandBatch.Clear(); |
||||
} |
||||
|
||||
protected override void TerminateBatching() |
||||
{ |
||||
ClearBatch(); |
||||
commandBatch = null; |
||||
} |
||||
|
||||
protected override IDataParameter GetBatchedParameter(int commandIdentifier, int parameterIndex) |
||||
{ |
||||
return (IDataParameter)commandBatch[commandIdentifier].Parameters[parameterIndex]; |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
/// <summary> |
||||
/// Overridden. See <see cref="DbDataAdapter.CreateRowUpdatedEvent"/>. |
||||
/// </summary> |
||||
/// <param name="dataRow"></param> |
||||
/// <param name="command"></param> |
||||
/// <param name="statementType"></param> |
||||
/// <param name="tableMapping"></param> |
||||
/// <returns></returns> |
||||
override protected RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) |
||||
{ |
||||
return new MySqlRowUpdatedEventArgs(dataRow, command, statementType, tableMapping); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Overridden. See <see cref="DbDataAdapter.CreateRowUpdatingEvent"/>. |
||||
/// </summary> |
||||
/// <param name="dataRow"></param> |
||||
/// <param name="command"></param> |
||||
/// <param name="statementType"></param> |
||||
/// <param name="tableMapping"></param> |
||||
/// <returns></returns> |
||||
override protected RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) |
||||
{ |
||||
return new MySqlRowUpdatingEventArgs(dataRow, command, statementType, tableMapping); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Overridden. Raises the RowUpdating event. |
||||
/// </summary> |
||||
/// <param name="value">A MySqlRowUpdatingEventArgs that contains the event data.</param> |
||||
override protected void OnRowUpdating(RowUpdatingEventArgs value) |
||||
{ |
||||
if (RowUpdating != null) |
||||
RowUpdating(this, (value as MySqlRowUpdatingEventArgs)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Overridden. Raises the RowUpdated event. |
||||
/// </summary> |
||||
/// <param name="value">A MySqlRowUpdatedEventArgs that contains the event data. </param> |
||||
override protected void OnRowUpdated(RowUpdatedEventArgs value) |
||||
{ |
||||
if (RowUpdated != null) |
||||
RowUpdated(this, (value as MySqlRowUpdatedEventArgs)); |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Represents the method that will handle the <see cref="MySqlDataAdapter.RowUpdating"/> event of a <see cref="MySqlDataAdapter"/>. |
||||
/// </summary> |
||||
public delegate void MySqlRowUpdatingEventHandler(object sender, MySqlRowUpdatingEventArgs e); |
||||
|
||||
/// <summary> |
||||
/// Represents the method that will handle the <see cref="MySqlDataAdapter.RowUpdated"/> event of a <see cref="MySqlDataAdapter"/>. |
||||
/// </summary> |
||||
public delegate void MySqlRowUpdatedEventHandler(object sender, MySqlRowUpdatedEventArgs e); |
||||
|
||||
/// <summary> |
||||
/// Provides data for the RowUpdating event. This class cannot be inherited. |
||||
/// </summary> |
||||
public sealed class MySqlRowUpdatingEventArgs : RowUpdatingEventArgs |
||||
{ |
||||
/// <summary> |
||||
/// Initializes a new instance of the MySqlRowUpdatingEventArgs class. |
||||
/// </summary> |
||||
/// <param name="row">The <see cref="DataRow"/> to |
||||
/// <see cref="DbDataAdapter.Update(DataSet)"/>.</param> |
||||
/// <param name="command">The <see cref="IDbCommand"/> to execute during <see cref="DbDataAdapter.Update(DataSet)"/>.</param> |
||||
/// <param name="statementType">One of the <see cref="StatementType"/> values that specifies the type of query executed.</param> |
||||
/// <param name="tableMapping">The <see cref="DataTableMapping"/> sent through an <see cref="DbDataAdapter.Update(DataSet)"/>.</param> |
||||
public MySqlRowUpdatingEventArgs(DataRow row, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) |
||||
: base(row, command, statementType, tableMapping) |
||||
{ |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the MySqlCommand to execute when performing the Update. |
||||
/// </summary> |
||||
new public MySqlCommand Command |
||||
{ |
||||
get { return (MySqlCommand)base.Command; } |
||||
set { base.Command = value; } |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Provides data for the RowUpdated event. This class cannot be inherited. |
||||
/// </summary> |
||||
public sealed class MySqlRowUpdatedEventArgs : RowUpdatedEventArgs |
||||
{ |
||||
/// <summary> |
||||
/// Initializes a new instance of the MySqlRowUpdatedEventArgs class. |
||||
/// </summary> |
||||
/// <param name="row">The <see cref="DataRow"/> sent through an <see cref="DbDataAdapter.Update(DataSet)"/>.</param> |
||||
/// <param name="command">The <see cref="IDbCommand"/> executed when <see cref="DbDataAdapter.Update(DataSet)"/> is called.</param> |
||||
/// <param name="statementType">One of the <see cref="StatementType"/> values that specifies the type of query executed.</param> |
||||
/// <param name="tableMapping">The <see cref="DataTableMapping"/> sent through an <see cref="DbDataAdapter.Update(DataSet)"/>.</param> |
||||
public MySqlRowUpdatedEventArgs(DataRow row, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) |
||||
: base(row, command, statementType, tableMapping) |
||||
{ |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets or sets the MySqlCommand executed when Update is called. |
||||
/// </summary> |
||||
new public MySqlCommand Command |
||||
{ |
||||
get { return (MySqlCommand)base.Command; } |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,924 @@ |
||||
// Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify |
||||
// it under the terms of the GNU General Public License version 2 as published by |
||||
// the Free Software Foundation |
||||
// |
||||
// There are special exceptions to the terms and conditions of the GPL |
||||
// as it is applied to this software. View the full text of the |
||||
// exception in file EXCEPTIONS in the directory of this software |
||||
// distribution. |
||||
// |
||||
// This program is distributed in the hope that it will be useful, |
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
// GNU General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU General Public License |
||||
// along with this program; if not, write to the Free Software |
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
using System; |
||||
using System.Data; |
||||
using System.Data.Common; |
||||
using System.Collections; |
||||
using MySql.Data.Types; |
||||
using System.Data.SqlTypes; |
||||
using System.Collections.Generic; |
||||
using System.Globalization; |
||||
using MySql.Data.MySqlClient.Properties; |
||||
|
||||
namespace MySql.Data.MySqlClient |
||||
{ |
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/ClassSummary/*'/> |
||||
public sealed class MySqlDataReader : DbDataReader, IDataReader, IDataRecord |
||||
{ |
||||
// The DataReader should always be open when returned to the user. |
||||
private bool isOpen = true; |
||||
|
||||
private CommandBehavior commandBehavior; |
||||
private MySqlCommand command; |
||||
internal long affectedRows; |
||||
internal Driver driver; |
||||
private PreparableStatement statement; |
||||
private ResultSet resultSet; |
||||
|
||||
/* |
||||
* Keep track of the connection in order to implement the |
||||
* CommandBehavior.CloseConnection flag. A null reference means |
||||
* normal behavior (do not automatically close). |
||||
*/ |
||||
private MySqlConnection connection; |
||||
|
||||
/* |
||||
* Because the user should not be able to directly create a |
||||
* DataReader object, the constructors are |
||||
* marked as internal. |
||||
*/ |
||||
internal MySqlDataReader(MySqlCommand cmd, PreparableStatement statement, CommandBehavior behavior) |
||||
{ |
||||
this.command = cmd; |
||||
connection = (MySqlConnection)command.Connection; |
||||
commandBehavior = behavior; |
||||
driver = connection.driver; |
||||
affectedRows = -1; |
||||
this.statement = statement; |
||||
} |
||||
|
||||
#region Properties |
||||
|
||||
internal PreparableStatement Statement |
||||
{ |
||||
get { return statement; } |
||||
} |
||||
|
||||
internal MySqlCommand Command |
||||
{ |
||||
get { return command; } |
||||
} |
||||
|
||||
internal ResultSet ResultSet |
||||
{ |
||||
get { return resultSet; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets a value indicating the depth of nesting for the current row. This method is not |
||||
/// supported currently and always returns 0. |
||||
/// </summary> |
||||
public override int Depth |
||||
{ |
||||
get { return 0; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the number of columns in the current row. |
||||
/// </summary> |
||||
public override int FieldCount |
||||
{ |
||||
get { return resultSet == null ? 0 : resultSet.Size; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets a value indicating whether the MySqlDataReader contains one or more rows. |
||||
/// </summary> |
||||
public override bool HasRows |
||||
{ |
||||
get { return resultSet == null ? false : resultSet.HasRows; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets a value indicating whether the data reader is closed. |
||||
/// </summary> |
||||
public override bool IsClosed |
||||
{ |
||||
get { return !isOpen; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. |
||||
/// </summary> |
||||
public override int RecordsAffected |
||||
{ |
||||
// RecordsAffected returns the number of rows affected in batch |
||||
// statments from insert/delete/update statments. This property |
||||
// is not completely accurate until .Close() has been called. |
||||
get { return (int)affectedRows; } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Overloaded. Gets the value of a column in its native format. |
||||
/// In C#, this property is the indexer for the MySqlDataReader class. |
||||
/// </summary> |
||||
public override object this[int i] |
||||
{ |
||||
get { return GetValue(i); } |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of a column in its native format. |
||||
/// [C#] In C#, this property is the indexer for the MySqlDataReader class. |
||||
/// </summary> |
||||
public override object this[String name] |
||||
{ |
||||
// Look up the ordinal and return |
||||
// the value at that position. |
||||
get { return this[GetOrdinal(name)]; } |
||||
} |
||||
|
||||
#endregion |
||||
|
||||
/// <summary> |
||||
/// Closes the MySqlDataReader object. |
||||
/// </summary> |
||||
public override void Close() |
||||
{ |
||||
if (!isOpen) return; |
||||
|
||||
bool shouldCloseConnection = (commandBehavior & CommandBehavior.CloseConnection) != 0; |
||||
commandBehavior = CommandBehavior.Default; |
||||
|
||||
// clear all remaining resultsets |
||||
try |
||||
{ |
||||
while (NextResult()) { } |
||||
} |
||||
catch (MySqlException ex) |
||||
{ |
||||
if (ex.Number != 1317) |
||||
throw; |
||||
} |
||||
|
||||
connection.Reader = null; |
||||
// we now give the command a chance to terminate. In the case of |
||||
// stored procedures it needs to update out and inout parameters |
||||
command.Close(this); |
||||
|
||||
if (shouldCloseConnection) |
||||
connection.Close(); |
||||
|
||||
command = null; |
||||
connection = null; |
||||
isOpen = false; |
||||
} |
||||
|
||||
#region TypeSafe Accessors |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column as a Boolean. |
||||
/// </summary> |
||||
/// <param name="name"></param> |
||||
/// <returns></returns> |
||||
public bool GetBoolean(string name) |
||||
{ |
||||
return GetBoolean(GetOrdinal(name)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column as a Boolean. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public override bool GetBoolean(int i) |
||||
{ |
||||
return Convert.ToBoolean(GetValue(i)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column as a byte. |
||||
/// </summary> |
||||
/// <param name="name"></param> |
||||
/// <returns></returns> |
||||
public byte GetByte(string name) |
||||
{ |
||||
return GetByte(GetOrdinal(name)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column as a byte. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public override byte GetByte(int i) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(i, false); |
||||
if (v is MySqlUByte) |
||||
return ((MySqlUByte)v).Value; |
||||
else |
||||
return (byte)((MySqlByte)v).Value; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column as a sbyte. |
||||
/// </summary> |
||||
/// <param name="name"></param> |
||||
/// <returns></returns> |
||||
public sbyte GetSByte(string name) |
||||
{ |
||||
return GetSByte(GetOrdinal(name)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column as a sbyte. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public sbyte GetSByte(int i) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(i, false); |
||||
if (v is MySqlByte) |
||||
return ((MySqlByte)v).Value; |
||||
else |
||||
return (sbyte)((MySqlByte)v).Value; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Reads a stream of bytes from the specified column offset into the buffer an array starting at the given buffer offset. |
||||
/// </summary> |
||||
/// <param name="i">The zero-based column ordinal. </param> |
||||
/// <param name="fieldOffset">The index within the field from which to begin the read operation. </param> |
||||
/// <param name="buffer">The buffer into which to read the stream of bytes. </param> |
||||
/// <param name="bufferoffset">The index for buffer to begin the read operation. </param> |
||||
/// <param name="length">The maximum length to copy into the buffer. </param> |
||||
/// <returns>The actual number of bytes read.</returns> |
||||
/// <include file='docs/MySqlDataReader.xml' path='MyDocs/MyMembers[@name="GetBytes"]/*'/> |
||||
public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) |
||||
{ |
||||
if (i >= FieldCount) |
||||
throw new IndexOutOfRangeException(); |
||||
|
||||
IMySqlValue val = GetFieldValue(i, false); |
||||
|
||||
if (!(val is MySqlBinary) && !(val is MySqlGuid)) |
||||
throw new MySqlException("GetBytes can only be called on binary or guid columns"); |
||||
|
||||
byte[] bytes = null; |
||||
if (val is MySqlBinary) |
||||
bytes = ((MySqlBinary)val).Value; |
||||
else |
||||
bytes = ((MySqlGuid)val).Bytes; |
||||
|
||||
if (buffer == null) |
||||
return bytes.Length; |
||||
|
||||
if (bufferoffset >= buffer.Length || bufferoffset < 0) |
||||
throw new IndexOutOfRangeException("Buffer index must be a valid index in buffer"); |
||||
if (buffer.Length < (bufferoffset + length)) |
||||
throw new ArgumentException("Buffer is not large enough to hold the requested data"); |
||||
if (fieldOffset < 0 || |
||||
((ulong)fieldOffset >= (ulong)bytes.Length && (ulong)bytes.Length > 0)) |
||||
throw new IndexOutOfRangeException("Data index must be a valid index in the field"); |
||||
|
||||
// adjust the length so we don't run off the end |
||||
if ((ulong)bytes.Length < (ulong)(fieldOffset + length)) |
||||
{ |
||||
length = (int)((ulong)bytes.Length - (ulong)fieldOffset); |
||||
} |
||||
|
||||
Buffer.BlockCopy(bytes, (int)fieldOffset, buffer, (int)bufferoffset, (int)length); |
||||
|
||||
return length; |
||||
} |
||||
|
||||
private object ChangeType(IMySqlValue value, int fieldIndex, Type newType) |
||||
{ |
||||
#if !CF |
||||
resultSet.Fields[fieldIndex].AddTypeConversion(newType); |
||||
#endif |
||||
return Convert.ChangeType(value.Value, newType, CultureInfo.InvariantCulture); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column as a single character. |
||||
/// </summary> |
||||
/// <param name="name"></param> |
||||
/// <returns></returns> |
||||
public char GetChar(string name) |
||||
{ |
||||
return GetChar(GetOrdinal(name)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column as a single character. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public override char GetChar(int i) |
||||
{ |
||||
string s = GetString(i); |
||||
return s[0]; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Reads a stream of characters from the specified column offset into the buffer as an array starting at the given buffer offset. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <param name="fieldoffset"></param> |
||||
/// <param name="buffer"></param> |
||||
/// <param name="bufferoffset"></param> |
||||
/// <param name="length"></param> |
||||
/// <returns></returns> |
||||
public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) |
||||
{ |
||||
if (i >= FieldCount) |
||||
throw new IndexOutOfRangeException(); |
||||
|
||||
string valAsString = GetString(i); |
||||
|
||||
if (buffer == null) return valAsString.Length; |
||||
|
||||
if (bufferoffset >= buffer.Length || bufferoffset < 0) |
||||
throw new IndexOutOfRangeException("Buffer index must be a valid index in buffer"); |
||||
if (buffer.Length < (bufferoffset + length)) |
||||
throw new ArgumentException("Buffer is not large enough to hold the requested data"); |
||||
if (fieldoffset < 0 || fieldoffset >= valAsString.Length) |
||||
throw new IndexOutOfRangeException("Field offset must be a valid index in the field"); |
||||
|
||||
if (valAsString.Length < length) |
||||
length = valAsString.Length; |
||||
valAsString.CopyTo((int)fieldoffset, buffer, bufferoffset, length); |
||||
return length; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the name of the source data type. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public override String GetDataTypeName(int i) |
||||
{ |
||||
if (!isOpen) throw new Exception("No current query in data reader"); |
||||
if (i >= FieldCount) throw new IndexOutOfRangeException(); |
||||
|
||||
// return the name of the type used on the backend |
||||
IMySqlValue v = resultSet.Values[i]; |
||||
return v.MySqlTypeName; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetMySqlDateTime/*'/> |
||||
public MySqlDateTime GetMySqlDateTime(string column) |
||||
{ |
||||
return GetMySqlDateTime(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetMySqlDateTime/*'/> |
||||
public MySqlDateTime GetMySqlDateTime(int column) |
||||
{ |
||||
return (MySqlDateTime)GetFieldValue(column, true); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetDateTimeS/*'/> |
||||
public DateTime GetDateTime(string column) |
||||
{ |
||||
return GetDateTime(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetDateTime/*'/> |
||||
public override DateTime GetDateTime(int i) |
||||
{ |
||||
IMySqlValue val = GetFieldValue(i, true); |
||||
MySqlDateTime dt; |
||||
|
||||
if (val is MySqlDateTime) |
||||
dt = (MySqlDateTime)val; |
||||
else |
||||
{ |
||||
// we need to do this because functions like date_add return string |
||||
string s = GetString(i); |
||||
dt = MySqlDateTime.Parse(s); |
||||
} |
||||
|
||||
if (connection.Settings.ConvertZeroDateTime && !dt.IsValidDateTime) |
||||
return DateTime.MinValue; |
||||
else |
||||
return dt.GetDateTime(); |
||||
} |
||||
|
||||
public MySqlDecimal GetMySqlDecimal(string column) |
||||
{ |
||||
return GetMySqlDecimal(GetOrdinal(column)); |
||||
} |
||||
|
||||
public MySqlDecimal GetMySqlDecimal(int i) |
||||
{ |
||||
return (MySqlDecimal)GetFieldValue(i, false); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetDecimalS/*'/> |
||||
public Decimal GetDecimal(string column) |
||||
{ |
||||
return GetDecimal(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetDecimal/*'/> |
||||
public override Decimal GetDecimal(int i) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(i, true); |
||||
if (v is MySqlDecimal) |
||||
return ((MySqlDecimal)v).Value; |
||||
return Convert.ToDecimal(v.Value); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetDoubleS/*'/> |
||||
public double GetDouble(string column) |
||||
{ |
||||
return GetDouble(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetDouble/*'/> |
||||
public override double GetDouble(int i) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(i, true); |
||||
if (v is MySqlDouble) |
||||
return ((MySqlDouble)v).Value; |
||||
return Convert.ToDouble(v.Value); |
||||
} |
||||
|
||||
public Type GetFieldType(string column) |
||||
{ |
||||
return GetFieldType(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the Type that is the data type of the object. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public override Type GetFieldType(int i) |
||||
{ |
||||
if (!isOpen) throw new Exception("No current query in data reader"); |
||||
if (i >= FieldCount) throw new IndexOutOfRangeException(); |
||||
|
||||
// we have to use the values array directly because we can't go through |
||||
// GetValue |
||||
IMySqlValue v = resultSet.Values[i]; |
||||
if (v is MySqlDateTime) |
||||
{ |
||||
if (!connection.Settings.AllowZeroDateTime) |
||||
return typeof(DateTime); |
||||
return typeof(MySqlDateTime); |
||||
} |
||||
return v.SystemType; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetFloatS/*'/> |
||||
public float GetFloat(string column) |
||||
{ |
||||
return GetFloat(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetFloat/*'/> |
||||
public override float GetFloat(int i) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(i, true); |
||||
if (v is MySqlSingle) |
||||
return ((MySqlSingle)v).Value; |
||||
return Convert.ToSingle(v.Value); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetGuidS/*'/> |
||||
public Guid GetGuid(string column) |
||||
{ |
||||
return GetGuid(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetGuid/*'/> |
||||
public override Guid GetGuid(int i) |
||||
{ |
||||
object v = GetValue(i); |
||||
if (v is Guid) |
||||
return (Guid)v; |
||||
if (v is string) |
||||
return new Guid(v as string); |
||||
if (v is byte[]) |
||||
{ |
||||
byte[] bytes = (byte[])v; |
||||
if (bytes.Length == 16) |
||||
return new Guid(bytes); |
||||
} |
||||
throw new MySqlException(Resources.ValueNotSupportedForGuid); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetInt16S/*'/> |
||||
public Int16 GetInt16(string column) |
||||
{ |
||||
return GetInt16(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetInt16/*'/> |
||||
public override Int16 GetInt16(int i) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(i, true); |
||||
if (v is MySqlInt16) |
||||
return ((MySqlInt16)v).Value; |
||||
|
||||
return (short)ChangeType(v, i, typeof(short)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetInt32S/*'/> |
||||
public Int32 GetInt32(string column) |
||||
{ |
||||
return GetInt32(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetInt32/*'/> |
||||
public override Int32 GetInt32(int i) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(i, true); |
||||
if (v is MySqlInt32) |
||||
return ((MySqlInt32)v).Value; |
||||
|
||||
return (Int32)ChangeType(v, i, typeof(Int32)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetInt64S/*'/> |
||||
public Int64 GetInt64(string column) |
||||
{ |
||||
return GetInt64(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetInt64/*'/> |
||||
public override Int64 GetInt64(int i) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(i, true); |
||||
if (v is MySqlInt64) |
||||
return ((MySqlInt64)v).Value; |
||||
|
||||
return (Int64)ChangeType(v, i, typeof(Int64)); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the name of the specified column. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public override String GetName(int i) |
||||
{ |
||||
if (!isOpen) throw new Exception("No current query in data reader"); |
||||
if (i >= FieldCount) throw new IndexOutOfRangeException(); |
||||
|
||||
return resultSet.Fields[i].ColumnName; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the column ordinal, given the name of the column. |
||||
/// </summary> |
||||
/// <param name="name"></param> |
||||
/// <returns></returns> |
||||
public override int GetOrdinal(string name) |
||||
{ |
||||
if (!isOpen || resultSet == null) |
||||
throw new Exception("No current query in data reader"); |
||||
|
||||
return resultSet.GetOrdinal(name); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Returns a DataTable that describes the column metadata of the MySqlDataReader. |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
public override DataTable GetSchemaTable() |
||||
{ |
||||
// Only Results from SQL SELECT Queries |
||||
// get a DataTable for schema of the result |
||||
// otherwise, DataTable is null reference |
||||
if (FieldCount == 0) return null; |
||||
|
||||
DataTable dataTableSchema = new DataTable("SchemaTable"); |
||||
|
||||
dataTableSchema.Columns.Add("ColumnName", typeof(string)); |
||||
dataTableSchema.Columns.Add("ColumnOrdinal", typeof(int)); |
||||
dataTableSchema.Columns.Add("ColumnSize", typeof(int)); |
||||
dataTableSchema.Columns.Add("NumericPrecision", typeof(int)); |
||||
dataTableSchema.Columns.Add("NumericScale", typeof(int)); |
||||
dataTableSchema.Columns.Add("IsUnique", typeof(bool)); |
||||
dataTableSchema.Columns.Add("IsKey", typeof(bool)); |
||||
DataColumn dc = dataTableSchema.Columns["IsKey"]; |
||||
dc.AllowDBNull = true; // IsKey can have a DBNull |
||||
dataTableSchema.Columns.Add("BaseCatalogName", typeof(string)); |
||||
dataTableSchema.Columns.Add("BaseColumnName", typeof(string)); |
||||
dataTableSchema.Columns.Add("BaseSchemaName", typeof(string)); |
||||
dataTableSchema.Columns.Add("BaseTableName", typeof(string)); |
||||
dataTableSchema.Columns.Add("DataType", typeof(Type)); |
||||
dataTableSchema.Columns.Add("AllowDBNull", typeof(bool)); |
||||
dataTableSchema.Columns.Add("ProviderType", typeof(int)); |
||||
dataTableSchema.Columns.Add("IsAliased", typeof(bool)); |
||||
dataTableSchema.Columns.Add("IsExpression", typeof(bool)); |
||||
dataTableSchema.Columns.Add("IsIdentity", typeof(bool)); |
||||
dataTableSchema.Columns.Add("IsAutoIncrement", typeof(bool)); |
||||
dataTableSchema.Columns.Add("IsRowVersion", typeof(bool)); |
||||
dataTableSchema.Columns.Add("IsHidden", typeof(bool)); |
||||
dataTableSchema.Columns.Add("IsLong", typeof(bool)); |
||||
dataTableSchema.Columns.Add("IsReadOnly", typeof(bool)); |
||||
|
||||
int ord = 1; |
||||
for (int i = 0; i < FieldCount; i++) |
||||
{ |
||||
MySqlField f = resultSet.Fields[i]; |
||||
DataRow r = dataTableSchema.NewRow(); |
||||
r["ColumnName"] = f.ColumnName; |
||||
r["ColumnOrdinal"] = ord++; |
||||
r["ColumnSize"] = f.IsTextField ? f.ColumnLength / f.MaxLength : f.ColumnLength; |
||||
int prec = f.Precision; |
||||
int pscale = f.Scale; |
||||
if (prec != -1) |
||||
r["NumericPrecision"] = (short)prec; |
||||
if (pscale != -1) |
||||
r["NumericScale"] = (short)pscale; |
||||
r["DataType"] = GetFieldType(i); |
||||
r["ProviderType"] = (int)f.Type; |
||||
r["IsLong"] = f.IsBlob && f.ColumnLength > 255; |
||||
r["AllowDBNull"] = f.AllowsNull; |
||||
r["IsReadOnly"] = false; |
||||
r["IsRowVersion"] = false; |
||||
r["IsUnique"] = f.IsUnique; |
||||
r["IsKey"] = f.IsPrimaryKey; |
||||
r["IsAutoIncrement"] = f.IsAutoIncrement; |
||||
r["BaseSchemaName"] = f.DatabaseName; |
||||
r["BaseCatalogName"] = null; |
||||
r["BaseTableName"] = f.RealTableName; |
||||
r["BaseColumnName"] = f.OriginalColumnName; |
||||
|
||||
dataTableSchema.Rows.Add(r); |
||||
} |
||||
|
||||
return dataTableSchema; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetStringS/*'/> |
||||
public string GetString(string column) |
||||
{ |
||||
return GetString(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetString/*'/> |
||||
public override String GetString(int i) |
||||
{ |
||||
IMySqlValue val = GetFieldValue(i, true); |
||||
|
||||
if (val is MySqlBinary) |
||||
{ |
||||
byte[] v = ((MySqlBinary)val).Value; |
||||
return resultSet.Fields[i].Encoding.GetString(v, 0, v.Length); |
||||
} |
||||
|
||||
return val.Value.ToString(); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetTimeSpan/*'/> |
||||
public TimeSpan GetTimeSpan(string column) |
||||
{ |
||||
return GetTimeSpan(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetTimeSpan/*'/> |
||||
public TimeSpan GetTimeSpan(int column) |
||||
{ |
||||
IMySqlValue val = GetFieldValue(column, true); |
||||
|
||||
MySqlTimeSpan ts = (MySqlTimeSpan)val; |
||||
return ts.Value; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets the value of the specified column in its native format. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public override object GetValue(int i) |
||||
{ |
||||
if (!isOpen) throw new Exception("No current query in data reader"); |
||||
if (i >= FieldCount) throw new IndexOutOfRangeException(); |
||||
|
||||
IMySqlValue val = GetFieldValue(i, false); |
||||
if (val.IsNull) |
||||
return DBNull.Value; |
||||
|
||||
// if the column is a date/time, then we return a MySqlDateTime |
||||
// so .ToString() will print '0000-00-00' correctly |
||||
if (val is MySqlDateTime) |
||||
{ |
||||
MySqlDateTime dt = (MySqlDateTime)val; |
||||
if (!dt.IsValidDateTime && connection.Settings.ConvertZeroDateTime) |
||||
return DateTime.MinValue; |
||||
else if (connection.Settings.AllowZeroDateTime) |
||||
return val; |
||||
else |
||||
return dt.GetDateTime(); |
||||
} |
||||
|
||||
return val.Value; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets all attribute columns in the collection for the current row. |
||||
/// </summary> |
||||
/// <param name="values"></param> |
||||
/// <returns></returns> |
||||
public override int GetValues(object[] values) |
||||
{ |
||||
int numCols = Math.Min(values.Length, FieldCount); |
||||
for (int i = 0; i < numCols; i++) |
||||
values[i] = GetValue(i); |
||||
|
||||
return numCols; |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetUInt16/*'/> |
||||
public UInt16 GetUInt16(string column) |
||||
{ |
||||
return GetUInt16(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetUInt16/*'/> |
||||
public UInt16 GetUInt16(int column) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(column, true); |
||||
if (v is MySqlUInt16) |
||||
return ((MySqlUInt16)v).Value; |
||||
|
||||
return (UInt16)ChangeType(v, column, typeof(UInt16)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetUInt32/*'/> |
||||
public UInt32 GetUInt32(string column) |
||||
{ |
||||
return GetUInt32(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetUInt32/*'/> |
||||
public UInt32 GetUInt32(int column) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(column, true); |
||||
if (v is MySqlUInt32) |
||||
return ((MySqlUInt32)v).Value; |
||||
return (uint)ChangeType(v, column, typeof(UInt32)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetUInt64/*'/> |
||||
public UInt64 GetUInt64(string column) |
||||
{ |
||||
return GetUInt64(GetOrdinal(column)); |
||||
} |
||||
|
||||
/// <include file='docs/MySqlDataReader.xml' path='docs/GetUInt64/*'/> |
||||
public UInt64 GetUInt64(int column) |
||||
{ |
||||
IMySqlValue v = GetFieldValue(column, true); |
||||
if (v is MySqlUInt64) |
||||
return ((MySqlUInt64)v).Value; |
||||
|
||||
return (UInt64)ChangeType(v, column, typeof(UInt64)); |
||||
} |
||||
|
||||
|
||||
#endregion |
||||
|
||||
IDataReader IDataRecord.GetData(int i) |
||||
{ |
||||
return base.GetData(i); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Gets a value indicating whether the column contains non-existent or missing values. |
||||
/// </summary> |
||||
/// <param name="i"></param> |
||||
/// <returns></returns> |
||||
public override bool IsDBNull(int i) |
||||
{ |
||||
return DBNull.Value == GetValue(i); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Advances the data reader to the next result, when reading the results of batch SQL statements. |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
public override bool NextResult() |
||||
{ |
||||
if (!isOpen) |
||||
throw new MySqlException(Resources.NextResultIsClosed); |
||||
|
||||
// this will clear out any unread data |
||||
if (resultSet != null) |
||||
resultSet.Close(); |
||||
|
||||
// single result means we only return a single resultset. If we have already |
||||
// returned one, then we return false; |
||||
if (resultSet != null && (commandBehavior & CommandBehavior.SingleResult) != 0) |
||||
return false; |
||||
|
||||
// next load up the next resultset if any |
||||
try |
||||
{ |
||||
do |
||||
{ |
||||
resultSet = null; |
||||
resultSet = driver.NextResult(Statement.StatementId); |
||||
if (resultSet == null) return false; |
||||
if (resultSet.IsOutputParameters) return false; |
||||
|
||||
if (resultSet.Size == 0) |
||||
{ |
||||
Command.lastInsertedId = resultSet.InsertedId; |
||||
if (affectedRows == -1) |
||||
affectedRows = resultSet.AffectedRows; |
||||
else |
||||
affectedRows += resultSet.AffectedRows; |
||||
} |
||||
} while (resultSet.Size == 0); |
||||
|
||||
return true; |
||||
} |
||||
catch (MySqlException ex) |
||||
{ |
||||
if (ex.IsFatal) |
||||
connection.Abort(); |
||||
if (ex.Number == 0) |
||||
throw new MySqlException(Resources.FatalErrorReadingResult, ex); |
||||
throw; |
||||
} |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Advances the MySqlDataReader to the next record. |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
public override bool Read() |
||||
{ |
||||
if (!isOpen) |
||||
throw new MySqlException("Invalid attempt to Read when reader is closed."); |
||||
if (resultSet == null) |
||||
return false; |
||||
|
||||
try |
||||
{ |
||||
return resultSet.NextRow(commandBehavior); |
||||
} |
||||
catch (TimeoutException tex) |
||||
{ |
||||
connection.HandleTimeout(tex); |
||||
return false; // unreached |
||||
} |
||||
catch (MySqlException ex) |
||||
{ |
||||
if (ex.IsFatal) |
||||
connection.Abort(); |
||||
|
||||
// if we get a query interrupted then our resultset is done |
||||
if (ex.Number == 1317) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
throw new MySqlException(Resources.FatalErrorDuringRead, ex); |
||||
} |
||||
} |
||||
|
||||
|
||||
private IMySqlValue GetFieldValue(int index, bool checkNull) |
||||
{ |
||||
if (index < 0 || index >= FieldCount) |
||||
throw new ArgumentException(Resources.InvalidColumnOrdinal); |
||||
|
||||
IMySqlValue v = resultSet[index]; |
||||
|
||||
if (checkNull && v.IsNull) |
||||
throw new SqlNullValueException(); |
||||
|
||||
return v; |
||||
} |
||||
|
||||
#region IEnumerator |
||||
|
||||
/// <summary> |
||||
/// Returns an <see cref="IEnumerator"/> that iterates through the <see cref="MySqlDataReader"/>. |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
public override IEnumerator GetEnumerator() |
||||
{ |
||||
return new DbEnumerator(this, (commandBehavior & CommandBehavior.CloseConnection) != 0); |
||||
} |
||||
|
||||
#endregion |
||||
} |
||||
} |
@ -0,0 +1,934 @@ |
||||
<docs> |
||||
<ClassSummary> |
||||
<summary>Represents a SQL statement to execute against a MySQL database. This class cannot be inherited.</summary> |
||||
<remarks> |
||||
<B>MySqlCommand</B> features the following methods for executing commands at a MySQL database: |
||||
<list type="table"> |
||||
<listheader> |
||||
<term>Item</term> |
||||
<term>Description</term> |
||||
</listheader> |
||||
<item> |
||||
<term> |
||||
<a href="MySql.Data.MySqlClient.MySqlCommand.ExecuteReader_overloads.html">ExecuteReader</a> |
||||
</term> |
||||
<description>Executes commands that return rows.</description> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<a href="MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery.html">ExecuteNonQuery</a> |
||||
</term> |
||||
<description>Executes commands such as SQL INSERT, DELETE, and UPDATE statements.</description> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<a href="MySql.Data.MySqlClient.MySqlCommand.ExecuteScalar.html">ExecuteScalar</a> |
||||
</term> |
||||
<description>Retrieves a single value (for example, an aggregate value) from a database.</description> |
||||
</item> |
||||
</list> |
||||
|
||||
You can reset the <B>CommandText</B> property and reuse the <B>MySqlCommand</B> |
||||
object. However, you must close the <A |
||||
href="MySql.Data.MySqlClient.MySqlDataReader.html">MySqlDataReader</A> |
||||
before you can execute a new or previous command. |
||||
|
||||
If a <A href="MySql.Data.MySqlClient.MySqlException.html">MySqlException</A> is |
||||
generated by the method executing a <B>MySqlCommand</B>, the <A |
||||
href="MySql.Data.MySqlClient.MySqlConnection.html">MySqlConnection</A> |
||||
remains open. It is the responsibility of the programmer to close the connection. |
||||
|
||||
<note> |
||||
Using the '@' symbol for paramters is now the preferred approach although the old pattern of using |
||||
'?' is still supported. Please be aware though that using '@' can cause conflicts when user variables |
||||
are also used. To help with this situation please see the documentation on the 'allow user variables' |
||||
connection string option. The 'old syntax' connection string option has now been deprecated. |
||||
</note> |
||||
</remarks> |
||||
|
||||
<example> |
||||
The following example creates a <A href="frlrfsystemdatasqlclientsqlcommandclasstopic.htm">MySqlCommand</A> and |
||||
a <B>MySqlConnection</B>. The <B>MySqlConnection</B> is opened and set as the <A |
||||
href="frlrfsystemdatasqlclientsqlcommandclassconnectiontopic.htm">Connection</A> |
||||
for the <B>MySqlCommand</B>. The example then calls <A |
||||
href="frlrfsystemdatasqlclientsqlcommandclassexecutenonquerytopic.htm">ExecuteNonQuery</A>, |
||||
and closes the connection. To accomplish this, the <B>ExecuteNonQuery</B> is |
||||
passed a connection string and a query string that is a SQL INSERT |
||||
statement. |
||||
<code lang="vbnet"> |
||||
Public Sub InsertRow(myConnectionString As String) |
||||
" If the connection string is null, use a default. |
||||
If myConnectionString = "" Then |
||||
myConnectionString = "Database=Test;Data Source=localhost;User Id=username;Password=pass" |
||||
End If |
||||
Dim myConnection As New MySqlConnection(myConnectionString) |
||||
Dim myInsertQuery As String = "INSERT INTO Orders (id, customerId, amount) Values(1001, 23, 30.66)" |
||||
Dim myCommand As New MySqlCommand(myInsertQuery) |
||||
myCommand.Connection = myConnection |
||||
myConnection.Open() |
||||
myCommand.ExecuteNonQuery() |
||||
myCommand.Connection.Close() |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void InsertRow(string myConnectionString) |
||||
{ |
||||
// If the connection string is null, use a default. |
||||
if(myConnectionString == "") |
||||
{ |
||||
myConnectionString = "Database=Test;Data Source=localhost;User Id=username;Password=pass"; |
||||
} |
||||
MySqlConnection myConnection = new MySqlConnection(myConnectionString); |
||||
string myInsertQuery = "INSERT INTO Orders (id, customerId, amount) Values(1001, 23, 30.66)"; |
||||
MySqlCommand myCommand = new MySqlCommand(myInsertQuery); |
||||
myCommand.Connection = myConnection; |
||||
myConnection.Open(); |
||||
myCommand.ExecuteNonQuery(); |
||||
myCommand.Connection.Close(); |
||||
} |
||||
</code> |
||||
</example> |
||||
</ClassSummary> |
||||
|
||||
|
||||
|
||||
<ctor1> |
||||
<overloads> |
||||
<summary> |
||||
Initializes a new instance of the MySqlCommand class. |
||||
</summary> |
||||
<example> |
||||
The following example creates a MySqlCommand and sets some of its properties. |
||||
<para></para> |
||||
<note> |
||||
This example shows how to use one of the overloaded |
||||
versions of the MySqlCommand constructor. For other examples that might be available, |
||||
see the individual overload topics. |
||||
</note> |
||||
|
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand() |
||||
Dim myConnection As New MySqlConnection _ |
||||
("Persist Security Info=False;database=test;server=myServer") |
||||
myConnection.Open() |
||||
Dim myTrans As MySqlTransaction = myConnection.BeginTransaction() |
||||
Dim mySelectQuery As String = "SELECT * FROM MyTable" |
||||
Dim myCommand As New MySqlCommand(mySelectQuery, myConnection, myTrans) |
||||
myCommand.CommandTimeout = 20 |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand() |
||||
{ |
||||
MySqlConnection myConnection = new MySqlConnection("Persist Security Info=False; |
||||
database=test;server=myServer"); |
||||
myConnection.Open(); |
||||
MySqlTransaction myTrans = myConnection.BeginTransaction(); |
||||
string mySelectQuery = "SELECT * FROM myTable"; |
||||
MySqlCommand myCommand = new MySqlCommand(mySelectQuery, myConnection,myTrans); |
||||
myCommand.CommandTimeout = 20; |
||||
} |
||||
</code> |
||||
<code lang="C++"> |
||||
public: |
||||
void CreateMySqlCommand() |
||||
{ |
||||
MySqlConnection* myConnection = new MySqlConnection(S"Persist Security Info=False; |
||||
database=test;server=myServer"); |
||||
myConnection->Open(); |
||||
MySqlTransaction* myTrans = myConnection->BeginTransaction(); |
||||
String* mySelectQuery = S"SELECT * FROM myTable"; |
||||
MySqlCommand* myCommand = new MySqlCommand(mySelectQuery, myConnection, myTrans); |
||||
myCommand->CommandTimeout = 20; |
||||
}; |
||||
</code> |
||||
</example> |
||||
</overloads> |
||||
|
||||
|
||||
<summary> |
||||
Initializes a new instance of the MySqlCommand class. |
||||
</summary> |
||||
<remarks> |
||||
The base constructor initializes all fields to their default values. The |
||||
following table shows initial property values for an instance of <see cref="MySqlCommand"/>. |
||||
<list type="table"> |
||||
<listheader> |
||||
<term>Properties</term> |
||||
<term>Initial Value</term> |
||||
</listheader> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandText"/> |
||||
</term> |
||||
<term>empty string ("")</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandTimeout"/> |
||||
</term> |
||||
<term>0</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandType"/> |
||||
</term> |
||||
<term>CommandType.Text</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="Connection"/> |
||||
</term> |
||||
<term>Null</term> |
||||
</item> |
||||
</list> |
||||
<para> |
||||
You can change the value for any of these properties through a separate call to |
||||
the property. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and |
||||
sets some of its properties. |
||||
|
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand() |
||||
Dim myCommand As New MySqlCommand() |
||||
myCommand.CommandType = CommandType.Text |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand() |
||||
{ |
||||
MySqlCommand myCommand = new MySqlCommand(); |
||||
myCommand.CommandType = CommandType.Text; |
||||
} |
||||
</code> |
||||
</example> |
||||
</ctor1> |
||||
|
||||
<ctor2> |
||||
<summary> |
||||
Initializes a new instance of the <see cref="MySqlCommand"/> class with the text of the query. |
||||
</summary> |
||||
<param name="cmdText">The text of the query.</param> |
||||
<remarks> |
||||
When an instance of <see cref="MySqlCommand"/> is created, |
||||
the following read/write properties are set to initial values. |
||||
|
||||
<list type="table"> |
||||
<listheader> |
||||
<term>Properties</term> |
||||
<term>Initial Value</term> |
||||
</listheader> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandText"/> |
||||
</term> |
||||
<term> |
||||
<i>cmdText</i> |
||||
</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandTimeout"/> |
||||
</term> |
||||
<term>0</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandType"/> |
||||
</term> |
||||
<term>CommandType.Text</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="Connection"/> |
||||
</term> |
||||
<term>Null</term> |
||||
</item> |
||||
</list> |
||||
<para> |
||||
You can change the value for any of these properties through a separate call to |
||||
the property. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and |
||||
sets some of its properties. |
||||
|
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand() |
||||
Dim sql as String = "SELECT * FROM mytable" |
||||
Dim myCommand As New MySqlCommand(sql) |
||||
myCommand.CommandType = CommandType.Text |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand() |
||||
{ |
||||
string sql = "SELECT * FROM mytable"; |
||||
MySqlCommand myCommand = new MySqlCommand(sql); |
||||
myCommand.CommandType = CommandType.Text; |
||||
} |
||||
</code> |
||||
</example> |
||||
</ctor2> |
||||
|
||||
<ctor3> |
||||
<summary> |
||||
Initializes a new instance of the <see cref="MySqlCommand"/> class |
||||
with the text of the query and a <see cref="MySqlConnection"/>. |
||||
</summary> |
||||
<param name="cmdText">The text of the query.</param> |
||||
<param name="connection"> |
||||
A <see cref="MySqlConnection"/> that represents the |
||||
connection to an instance of SQL Server. |
||||
</param> |
||||
<remarks> |
||||
When an instance of <see cref="MySqlCommand"/> is created, |
||||
the following read/write properties are set to initial values. |
||||
|
||||
<list type="table"> |
||||
<listheader> |
||||
<term>Properties</term> |
||||
<term>Initial Value</term> |
||||
</listheader> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandText"/> |
||||
</term> |
||||
<term> |
||||
<i>cmdText</i> |
||||
</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandTimeout"/> |
||||
</term> |
||||
<term>0</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandType"/> |
||||
</term> |
||||
<term>CommandType.Text</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="Connection"/> |
||||
</term> |
||||
<term> |
||||
<i>connection</i> |
||||
</term> |
||||
</item> |
||||
</list> |
||||
<para> |
||||
You can change the value for any of these properties through a separate call to |
||||
the property. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and |
||||
sets some of its properties. |
||||
|
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand() |
||||
Dim conn as new MySqlConnection("server=myServer") |
||||
Dim sql as String = "SELECT * FROM mytable" |
||||
Dim myCommand As New MySqlCommand(sql, conn) |
||||
myCommand.CommandType = CommandType.Text |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand() |
||||
{ |
||||
MySqlConnection conn = new MySqlConnection("server=myserver") |
||||
string sql = "SELECT * FROM mytable"; |
||||
MySqlCommand myCommand = new MySqlCommand(sql, conn); |
||||
myCommand.CommandType = CommandType.Text; |
||||
} |
||||
</code> |
||||
</example> |
||||
|
||||
|
||||
</ctor3> |
||||
|
||||
<ctor4> |
||||
<summary> |
||||
Initializes a new instance of the <see cref="MySqlCommand"/> class |
||||
with the text of the query, a <see cref="MySqlConnection"/>, and the |
||||
<see cref="MySqlTransaction"/>. |
||||
</summary> |
||||
|
||||
<param name="cmdText">The text of the query.</param> |
||||
<param name="connection"> |
||||
A <see cref="MySqlConnection"/> that represents the |
||||
connection to an instance of SQL Server. |
||||
</param> |
||||
<param name="transaction"> |
||||
The <see cref="MySqlTransaction"/> in which the <see cref="MySqlCommand"/> executes. |
||||
</param> |
||||
<remarks> |
||||
When an instance of <see cref="MySqlCommand"/> is created, |
||||
the following read/write properties are set to initial values. |
||||
|
||||
<list type="table"> |
||||
<listheader> |
||||
<term>Properties</term> |
||||
<term>Initial Value</term> |
||||
</listheader> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandText"/> |
||||
</term> |
||||
<term> |
||||
<i>cmdText</i> |
||||
</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandTimeout"/> |
||||
</term> |
||||
<term>0</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="CommandType"/> |
||||
</term> |
||||
<term>CommandType.Text</term> |
||||
</item> |
||||
<item> |
||||
<term> |
||||
<see cref="Connection"/> |
||||
</term> |
||||
<term> |
||||
<i>connection</i> |
||||
</term> |
||||
</item> |
||||
</list> |
||||
<para> |
||||
You can change the value for any of these properties through a separate call to |
||||
the property. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and |
||||
sets some of its properties. |
||||
|
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand() |
||||
Dim conn as new MySqlConnection("server=myServer") |
||||
conn.Open(); |
||||
Dim txn as MySqlTransaction = conn.BeginTransaction() |
||||
Dim sql as String = "SELECT * FROM mytable" |
||||
Dim myCommand As New MySqlCommand(sql, conn, txn) |
||||
myCommand.CommandType = CommandType.Text |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand() |
||||
{ |
||||
MySqlConnection conn = new MySqlConnection("server=myserver") |
||||
conn.Open(); |
||||
MySqlTransaction txn = conn.BeginTransaction(); |
||||
string sql = "SELECT * FROM mytable"; |
||||
MySqlCommand myCommand = new MySqlCommand(sql, conn, txn); |
||||
myCommand.CommandType = CommandType.Text; |
||||
} |
||||
</code> |
||||
</example> |
||||
|
||||
</ctor4> |
||||
|
||||
|
||||
|
||||
|
||||
<ExecuteNonQuery> |
||||
<summary> |
||||
Executes a SQL statement against the connection and returns the number of rows affected. |
||||
</summary> |
||||
<returns>Number of rows affected</returns> |
||||
<remarks> |
||||
You can use ExecuteNonQuery to perform any type of database operation, |
||||
however any resultsets returned will not be available. Any output parameters |
||||
used in calling a stored procedure will be populated with data and can be |
||||
retrieved after execution is complete. |
||||
For UPDATE, INSERT, and DELETE statements, the return value is the number |
||||
of rows affected by the command. For all other types of statements, the return |
||||
value is -1. |
||||
</remarks> |
||||
<example> |
||||
The following example creates a MySqlCommand and then |
||||
executes it using ExecuteNonQuery. The example is passed a string that is a |
||||
SQL statement (such as UPDATE, INSERT, or DELETE) and a string to use to |
||||
connect to the data source. |
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand(myExecuteQuery As String, myConnection As MySqlConnection) |
||||
Dim myCommand As New MySqlCommand(myExecuteQuery, myConnection) |
||||
myCommand.Connection.Open() |
||||
myCommand.ExecuteNonQuery() |
||||
myConnection.Close() |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand(string myExecuteQuery, MySqlConnection myConnection) |
||||
{ |
||||
MySqlCommand myCommand = new MySqlCommand(myExecuteQuery, myConnection); |
||||
myCommand.Connection.Open(); |
||||
myCommand.ExecuteNonQuery(); |
||||
myConnection.Close(); |
||||
} |
||||
</code> |
||||
</example> |
||||
</ExecuteNonQuery> |
||||
|
||||
<ExecuteReader1> |
||||
<summary> |
||||
Sends the <see cref="CommandText"/> to the <see cref="MySqlConnection">Connection</see>, |
||||
and builds a <see cref="MySqlDataReader"/> using one of the <see cref="CommandBehavior"/> values. |
||||
</summary> |
||||
<param name="behavior"> |
||||
One of the <see cref="CommandBehavior"/> values. |
||||
</param> |
||||
<remarks> |
||||
<para> |
||||
When the <see cref="CommandType"/> property is set to <B>StoredProcedure</B>, |
||||
the <see cref="CommandText"/> property should be set to the name of the stored |
||||
procedure. The command executes this stored procedure when you call |
||||
<B>ExecuteReader</B>. |
||||
</para> |
||||
<para> |
||||
The <see cref="MySqlDataReader"/> supports a special mode that enables large binary |
||||
values to be read efficiently. For more information, see the <B>SequentialAccess</B> |
||||
setting for <see cref="CommandBehavior"/>. |
||||
</para> |
||||
<para> |
||||
While the <see cref="MySqlDataReader"/> is in use, the associated |
||||
<see cref="MySqlConnection"/> is busy serving the <B>MySqlDataReader</B>. |
||||
While in this state, no other operations can be performed on the |
||||
<B>MySqlConnection</B> other than closing it. This is the case until the |
||||
<see cref="MySqlDataReader.Close"/> method of the <B>MySqlDataReader</B> is called. |
||||
If the <B>MySqlDataReader</B> is created with <B>CommandBehavior</B> set to |
||||
<B>CloseConnection</B>, closing the <B>MySqlDataReader</B> closes the connection |
||||
automatically. |
||||
</para> |
||||
<note> |
||||
When calling ExecuteReader with the SingleRow behavior, you should be aware that using a <i>limit</i> |
||||
clause in your SQL will cause all rows (up to the limit given) to be retrieved by the client. The |
||||
<see cref="MySqlDataReader.Read"/> method will still return false after the first row but pulling all rows of data |
||||
into the client will have a performance impact. If the <i>limit</i> clause is not necessary, it should |
||||
be avoided. |
||||
</note> |
||||
</remarks> |
||||
<returns> |
||||
A <see cref="MySqlDataReader"/> object. |
||||
</returns> |
||||
</ExecuteReader1> |
||||
|
||||
|
||||
<ExecuteReader> |
||||
<summary> |
||||
Sends the <see cref="CommandText"/> to the <see cref="MySqlConnection">Connection</see> |
||||
and builds a <see cref="MySqlDataReader"/>. |
||||
</summary> |
||||
<returns> |
||||
A <see cref="MySqlDataReader"/> object. |
||||
</returns> |
||||
<remarks> |
||||
<para> |
||||
When the <see cref="CommandType"/> property is set to <B>StoredProcedure</B>, |
||||
the <see cref="CommandText"/> property should be set to the name of the stored |
||||
procedure. The command executes this stored procedure when you call |
||||
<B>ExecuteReader</B>. |
||||
</para> |
||||
<para> |
||||
While the <see cref="MySqlDataReader"/> is in use, the associated |
||||
<see cref="MySqlConnection"/> is busy serving the <B>MySqlDataReader</B>. |
||||
While in this state, no other operations can be performed on the |
||||
<B>MySqlConnection</B> other than closing it. This is the case until the |
||||
<see cref="MySqlDataReader.Close"/> method of the <B>MySqlDataReader</B> is called. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/>, then executes it by |
||||
passing a string that is a SQL SELECT statement, and a string to use to connect to the |
||||
data source. |
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlDataReader(mySelectQuery As String, myConnection As MySqlConnection) |
||||
Dim myCommand As New MySqlCommand(mySelectQuery, myConnection) |
||||
myConnection.Open() |
||||
Dim myReader As MySqlDataReader |
||||
myReader = myCommand.ExecuteReader() |
||||
Try |
||||
While myReader.Read() |
||||
Console.WriteLine(myReader.GetString(0)) |
||||
End While |
||||
Finally |
||||
myReader.Close |
||||
myConnection.Close |
||||
End Try |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlDataReader(string mySelectQuery, MySqlConnection myConnection) |
||||
{ |
||||
MySqlCommand myCommand = new MySqlCommand(mySelectQuery, myConnection); |
||||
myConnection.Open(); |
||||
MMySqlDataReader myReader; |
||||
myReader = myCommand.ExecuteReader(); |
||||
try |
||||
{ |
||||
while(myReader.Read()) |
||||
{ |
||||
Console.WriteLine(myReader.GetString(0)); |
||||
} |
||||
} |
||||
finally |
||||
{ |
||||
myReader.Close(); |
||||
myConnection.Close(); |
||||
} |
||||
} |
||||
</code> |
||||
</example> |
||||
</ExecuteReader> |
||||
|
||||
|
||||
<Prepare> |
||||
<summary> |
||||
Creates a prepared version of the command on an instance of MySQL Server. |
||||
</summary> |
||||
<remarks> |
||||
<para> |
||||
Prepared statements are only supported on MySQL version 4.1 and higher. Calling |
||||
prepare while connected to earlier versions of MySQL will succeed but will execute |
||||
the statement in the same way as unprepared. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example demonstrates the use of the <b>Prepare</b> method. |
||||
<code lang="VB.NET"> |
||||
public sub PrepareExample() |
||||
Dim cmd as New MySqlCommand("INSERT INTO mytable VALUES (@val)", myConnection) |
||||
cmd.Parameters.Add( "@val", 10 ) |
||||
cmd.Prepare() |
||||
cmd.ExecuteNonQuery() |
||||
|
||||
cmd.Parameters(0).Value = 20 |
||||
cmd.ExecuteNonQuery() |
||||
end sub |
||||
</code> |
||||
<code lang="C#"> |
||||
private void PrepareExample() |
||||
{ |
||||
MySqlCommand cmd = new MySqlCommand("INSERT INTO mytable VALUES (@val)", myConnection); |
||||
cmd.Parameters.Add( "@val", 10 ); |
||||
cmd.Prepare(); |
||||
cmd.ExecuteNonQuery(); |
||||
|
||||
cmd.Parameters[0].Value = 20; |
||||
cmd.ExecuteNonQuery(); |
||||
} |
||||
</code> |
||||
</example> |
||||
</Prepare> |
||||
|
||||
<ExecuteScalar> |
||||
<summary> |
||||
Executes the query, and returns the first column of the first row in the |
||||
result set returned by the query. Extra columns or rows are ignored. |
||||
</summary> |
||||
<returns> |
||||
The first column of the first row in the result set, or a null reference if the |
||||
result set is empty |
||||
</returns> |
||||
<remarks> |
||||
<para> |
||||
Use the <B>ExecuteScalar</B> method to retrieve a single value (for example, |
||||
an aggregate value) from a database. This requires less code than using the |
||||
<see cref="ExecuteReader()"/> method, and then performing the operations necessary |
||||
to generate the single value using the data returned by a <see cref="MySqlDataReader"/> |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and then |
||||
executes it using <B>ExecuteScalar</B>. The example is passed a string that is a |
||||
SQL statement that returns an aggregate result, and a string to use to |
||||
connect to the data source. |
||||
|
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand(myScalarQuery As String, myConnection As MySqlConnection) |
||||
Dim myCommand As New MySqlCommand(myScalarQuery, myConnection) |
||||
myCommand.Connection.Open() |
||||
myCommand.ExecuteScalar() |
||||
myConnection.Close() |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand(string myScalarQuery, MySqlConnection myConnection) |
||||
{ |
||||
MySqlCommand myCommand = new MySqlCommand(myScalarQuery, myConnection); |
||||
myCommand.Connection.Open(); |
||||
myCommand.ExecuteScalar(); |
||||
myConnection.Close(); |
||||
} |
||||
</code> |
||||
<code lang="C++"> |
||||
public: |
||||
void CreateMySqlCommand(String* myScalarQuery, MySqlConnection* myConnection) |
||||
{ |
||||
MySqlCommand* myCommand = new MySqlCommand(myScalarQuery, myConnection); |
||||
myCommand->Connection->Open(); |
||||
myCommand->ExecuteScalar(); |
||||
myConnection->Close(); |
||||
} |
||||
</code> |
||||
|
||||
</example> |
||||
</ExecuteScalar> |
||||
|
||||
<CommandText> |
||||
<summary> |
||||
Gets or sets the SQL statement to execute at the data source. |
||||
</summary> |
||||
<value> |
||||
The SQL statement or stored procedure to execute. The default is an empty string. |
||||
</value> |
||||
<remarks> |
||||
<para> |
||||
When the <see cref="CommandType"/> property is set to <B>StoredProcedure</B>, |
||||
the <B>CommandText</B> property should be set to the name of the stored procedure. |
||||
The user may be required to use escape character syntax if the stored procedure name |
||||
contains any special characters. The command executes this stored procedure when |
||||
you call one of the Execute methods. Starting with Connector/Net 5.0, having both a stored function |
||||
and stored procedure with the same name in the same database is not supported. It is |
||||
suggested that you provide unqiue names for your stored routines. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and sets some of its properties. |
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand() |
||||
Dim myCommand As New MySqlCommand() |
||||
myCommand.CommandText = "SELECT * FROM Mytable ORDER BY id" |
||||
myCommand.CommandType = CommandType.Text |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand() |
||||
{ |
||||
MySqlCommand myCommand = new MySqlCommand(); |
||||
myCommand.CommandText = "SELECT * FROM mytable ORDER BY id"; |
||||
myCommand.CommandType = CommandType.Text; |
||||
} |
||||
</code> |
||||
</example> |
||||
</CommandText> |
||||
|
||||
<CommandTimeout> |
||||
<summary> |
||||
Gets or sets the wait time before terminating the attempt to execute a command |
||||
and generating an error. |
||||
</summary> |
||||
<value> |
||||
The time (in seconds) to wait for the command to execute. The default is 30 |
||||
seconds. |
||||
</value> |
||||
<remarks> |
||||
CommandTimeout is dependent on the ability of MySQL to cancel an executing query. |
||||
Because of this, CommandTimeout is only supported when connected to MySQL |
||||
version 5.0.0 or higher. |
||||
</remarks> |
||||
</CommandTimeout> |
||||
|
||||
<CommandType> |
||||
<summary> |
||||
Gets or sets a value indicating how the <see cref="CommandText"/> property is to be interpreted. |
||||
</summary> |
||||
<value> |
||||
One of the <see cref="System.Data.CommandType"/> values. The default is <B>Text</B>. |
||||
</value> |
||||
<remarks> |
||||
<para> |
||||
When you set the <B>CommandType</B> property to <B>StoredProcedure</B>, you |
||||
should set the <see cref="CommandText"/> property to the name of the stored |
||||
procedure. The command executes this stored procedure when you call one of the |
||||
Execute methods. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and sets some of its properties. |
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand() |
||||
Dim myCommand As New MySqlCommand() |
||||
myCommand.CommandType = CommandType.Text |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand() |
||||
{ |
||||
MySqlCommand myCommand = new MySqlCommand(); |
||||
myCommand.CommandType = CommandType.Text; |
||||
} |
||||
</code> |
||||
</example> |
||||
</CommandType> |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<Connection> |
||||
<summary> |
||||
Gets or sets the <see cref="MySqlConnection"/> used by this instance of the |
||||
<see cref="MySqlCommand"/>. |
||||
</summary> |
||||
<value> |
||||
The connection to a data source. The default value is a null reference |
||||
(<B>Nothing</B> in Visual Basic). |
||||
</value> |
||||
<remarks> |
||||
<para> |
||||
If you set <B>Connection</B> while a transaction is in progress and the |
||||
<see cref="Transaction"/> property is not null, an <see cref="InvalidOperationException"/> |
||||
is generated. If the <B>Transaction</B> property is not null and the transaction |
||||
has already been committed or rolled back, <B>Transaction</B> is set to |
||||
null. |
||||
</para> |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and sets some of its properties. |
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand() |
||||
Dim mySelectQuery As String = "SELECT * FROM mytable ORDER BY id" |
||||
Dim myConnectString As String = "Persist Security Info=False;database=test;server=myServer" |
||||
Dim myCommand As New MySqlCommand(mySelectQuery) |
||||
myCommand.Connection = New MySqlConnection(myConnectString) |
||||
myCommand.CommandType = CommandType.Text |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand() |
||||
{ |
||||
string mySelectQuery = "SELECT * FROM mytable ORDER BY id"; |
||||
string myConnectString = "Persist Security Info=False;database=test;server=myServer"; |
||||
MySqlCommand myCommand = new MySqlCommand(mySelectQuery); |
||||
myCommand.Connection = new MySqlConnection(myConnectString); |
||||
myCommand.CommandType = CommandType.Text; |
||||
} |
||||
</code> |
||||
</example> |
||||
</Connection> |
||||
|
||||
<IsPrepared> |
||||
</IsPrepared> |
||||
|
||||
<LastInsertedId> |
||||
<summary>Provides the id of the last inserted row.</summary> |
||||
<value> |
||||
Id of the last inserted row. -1 if none exists. |
||||
</value> |
||||
<remarks> |
||||
An important point to remember is that this property can be used |
||||
in batch SQL scenarios but it's important to remember that it will |
||||
only reflect the insert id from the last insert statement in the batch. |
||||
|
||||
This property can also be used when the batch includes select statements |
||||
and ExecuteReader is used. This property can be consulted during result set |
||||
processing. |
||||
</remarks> |
||||
</LastInsertedId> |
||||
|
||||
<Parameters> |
||||
<summary> |
||||
Get the <see cref="MySqlParameterCollection"/> |
||||
</summary> |
||||
<value> |
||||
The parameters of the SQL statement or stored procedure. The default is |
||||
an empty collection. |
||||
</value> |
||||
<remarks> |
||||
Connector/Net does not support unnamed parameters. Every parameter added to the collection must |
||||
have an associated name. |
||||
</remarks> |
||||
<example> |
||||
The following example creates a <see cref="MySqlCommand"/> and displays its parameters. |
||||
To accomplish this, the method is passed a <see cref="MySqlConnection"/>, a query string |
||||
that is a SQL SELECT statement, and an array of <see cref="MySqlParameter"/> objects. |
||||
<code lang="vbnet"> |
||||
Public Sub CreateMySqlCommand(myConnection As MySqlConnection, _ |
||||
mySelectQuery As String, myParamArray() As MySqlParameter) |
||||
Dim myCommand As New MySqlCommand(mySelectQuery, myConnection) |
||||
myCommand.CommandText = "SELECT id, name FROM mytable WHERE age=@age" |
||||
myCommand.UpdatedRowSource = UpdateRowSource.Both |
||||
myCommand.Parameters.Add(myParamArray) |
||||
Dim j As Integer |
||||
For j = 0 To myCommand.Parameters.Count - 1 |
||||
myCommand.Parameters.Add(myParamArray(j)) |
||||
Next j |
||||
Dim myMessage As String = "" |
||||
Dim i As Integer |
||||
For i = 0 To myCommand.Parameters.Count - 1 |
||||
myMessage += myCommand.Parameters(i).ToString() & ControlChars.Cr |
||||
Next i |
||||
Console.WriteLine(myMessage) |
||||
End Sub |
||||
</code> |
||||
<code lang="C#"> |
||||
public void CreateMySqlCommand(MySqlConnection myConnection, string mySelectQuery, |
||||
MySqlParameter[] myParamArray) |
||||
{ |
||||
MySqlCommand myCommand = new MySqlCommand(mySelectQuery, myConnection); |
||||
myCommand.CommandText = "SELECT id, name FROM mytable WHERE age=@age"; |
||||
myCommand.Parameters.Add(myParamArray); |
||||
for (int j=0; j<myParamArray.Length; j++) |
||||
{ |
||||
myCommand.Parameters.Add(myParamArray[j]) ; |
||||
} |
||||
string myMessage = ""; |
||||
for (int i = 0; i < myCommand.Parameters.Count; i++) |
||||
{ |
||||
myMessage += myCommand.Parameters[i].ToString() + "\n"; |
||||
} |
||||
MessageBox.Show(myMessage); |
||||
} |
||||
</code> |
||||
</example> |
||||
</Parameters> |
||||
|
||||
<Transaction> |
||||
<summary> |
||||
Gets or sets the <see cref="MySqlTransaction"/> within which the <see cref="MySqlCommand"/> executes. |
||||
</summary> |
||||
<value> |
||||
The <see cref="MySqlTransaction"/>. The default value is a null reference (<B>Nothing</B> in Visual Basic). |
||||
</value> |
||||
<remarks> |
||||
You cannot set the <B>Transaction</B> property if it is already set to a |
||||
specific value, and the command is in the process of executing. If you set the |
||||
transaction property to a <see cref="MySqlTransaction"/> object that is not connected |
||||
to the same <see cref="MySqlConnection"/> as the <see cref="MySqlCommand"/> object, |
||||
an exception will be thrown the next time you attempt to execute a statement. |
||||
</remarks> |
||||
</Transaction> |
||||
|
||||
<UpdatedRowSource> |
||||
<summary> |
||||
Gets or sets how command results are applied to the <see cref="DataRow"/> |
||||
when used by the <see cref="System.Data.Common.DbDataAdapter.Update"/> method |
||||
of the <see cref="System.Data.Common.DbDataAdapter"/>. |
||||
</summary> |
||||
<value> |
||||
One of the <see cref="UpdateRowSource"/> values. |
||||
</value> |
||||
<remarks> |
||||
<para> |
||||
The default <see cref="System.Data.UpdateRowSource"/> value is |
||||
<B>Both</B> unless the command is automatically generated (as in the case of the |
||||
<see cref="MySqlCommandBuilder"/>), in which case the default is <B>None</B>. |
||||
</para> |
||||
</remarks> |
||||
</UpdatedRowSource> |
||||
|
||||
</docs> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,55 @@ |
||||
<docs> |
||||
<Server> |
||||
<summary> |
||||
Gets or sets the name or address of the MySQL instance to connect to. |
||||
</summary> |
||||
<remarks> |
||||
If this property is not set, then the provider will attempt to |
||||
connect to <b>localhost</b> even though this property will return |
||||
<b>String.Empty</b>. |
||||
</remarks> |
||||
<example> |
||||
</example> |
||||
</Server> |
||||
|
||||
<Database> |
||||
<summary> |
||||
Gets or sets the name of the database that should be selected |
||||
when the connection is first opened. |
||||
</summary> |
||||
<remarks> |
||||
There is no default for this property and, if not set, the |
||||
connection will not have a current database until one is set |
||||
using the <see cref="ChangeDatabase"/> method. |
||||
</remarks> |
||||
<example> |
||||
</example> |
||||
</Database> |
||||
|
||||
<ConnectionProtocol> |
||||
<summary> |
||||
Gets or sets the connection protocol that is being used for this |
||||
connection. |
||||
</summary> |
||||
<remarks> |
||||
</remarks> |
||||
<example> |
||||
</example> |
||||
</ConnectionProtocol> |
||||
|
||||
|
||||
<PipeName> |
||||
<summary> |
||||
Gets or sets the name of the named pipe object that the provider |
||||
should use. |
||||
</summary> |
||||
<remarks> |
||||
This property has no effect unless the <see cref="ConnectionProtocol"/> |
||||
property has been set to <b>NamedPipe</b>. |
||||
</remarks> |
||||
<example> |
||||
</example> |
||||
</PipeName> |
||||
|
||||
|
||||
</docs> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue