view release on metacpan or search on metacpan
SQLAnywhere.pm view on Meta::CPAN
=head2 Prepared Statement and Cursor Limits
To help detect handle leaks in client applications, SQL Anywhere
defaults to limiting the number of prepared statements and open
cursors that any connection can hold at one time to 50 of each. If
that limit is exceeded, a "Resource governor ... exceeded" error is
reported. If you encounter this error, make sure you are dropping all
of your statement handles and, if so, consult the SQL Anywhere
documentation for the MAX_CURSOR_COUNT and MAX_STATEMENT_COUNT
options.
view all matches for this distribution
view release on metacpan or search on metacpan
lib/DBD/SQLcipher/VirtualTable.pm view on Meta::CPAN
sub OPEN {
my $self = shift;
my $class = ref $self;
my $cursor_class = $class . "::Cursor";
return $cursor_class->NEW($self, @_);
}
#----------------------------------------------------------------------
# methods for insert/delete/update
lib/DBD/SQLcipher/VirtualTable.pm view on Meta::CPAN
}
sub FILTER {
my ($self, $idxNum, $idxStr, @values) = @_;
die "FILTER() should be redefined in cursor subclass";
}
sub EOF {
my ($self) = @_;
die "EOF() should be redefined in cursor subclass";
}
sub NEXT {
my ($self) = @_;
die "NEXT() should be redefined in cursor subclass";
}
sub COLUMN {
my ($self, $idxCol) = @_;
die "COLUMN() should be redefined in cursor subclass";
}
sub ROWID {
my ($self) = @_;
die "ROWID() should be redefined in cursor subclass";
}
1;
lib/DBD/SQLcipher/VirtualTable.pm view on Meta::CPAN
the B<table> class implements methods for creating or connecting
a virtual table, for destroying it, for opening new searches, etc.
=item *
the B<cursor> class implements methods for performing a specific
SQL statement
=back
lib/DBD/SQLcipher/VirtualTable.pm view on Meta::CPAN
by the sqlite kernel to decide about the best search strategy
=item b)
by the cursor L</FILTER> method to produce the desired subset
of rows from the virtual table.
=back
By calling this method, the SQLcipher core is saying to the virtual table
lib/DBD/SQLcipher/VirtualTable.pm view on Meta::CPAN
=over
=item C<argvIndex>
An index into the C<@values> array that will be passed to
the cursor's L</FILTER> method. In other words, if the current
constraint corresponds to the SQL fragment C<WHERE ... AND foo < 123 ...>,
and the corresponding C<argvIndex> takes value 5, this means that
the C<FILTER> method will receive C<123> in C<$values[5]>.
=item C<omit>
lib/DBD/SQLcipher/VirtualTable.pm view on Meta::CPAN
=head3 OPEN
Called to instanciate a new cursor.
The default implementation appends C<"::Cursor"> to the current
classname and calls C<NEW()> within that cursor class.
=head3 _SQLITE_UPDATE
This is the dispatch method implementing the C<xUpdate()> callback
for virtual tables. The default implementation applies the algorithm
lib/DBD/SQLcipher/VirtualTable.pm view on Meta::CPAN
=head2 Class methods
=head3 NEW
my $cursor = $cursor_class->NEW($vtable, @args)
Instanciates a new cursor.
The default implementation just returns a blessed hashref
with keys C<vtable> and C<args>.
=head2 Instance methods
=head3 FILTER
$cursor->FILTER($idxNum, $idxStr, @values);
This method begins a search of a virtual table.
The C<$idxNum> and C<$idxStr> arguments correspond to values returned
by L</BEST_INDEX> for the chosen index. The specific meanings of
lib/DBD/SQLcipher/VirtualTable.pm view on Meta::CPAN
expressions using the C<argvIndex> values of the
C<$constraints> list. Those values are passed to C<FILTER> through
the C<@values> array.
If the virtual table contains one or more rows that match the search
criteria, then the cursor must be left point at the first
row. Subsequent calls to L</EOF> must return false. If there are
no rows match, then the cursor must be left in a state that will cause
L</EOF> to return true. The SQLcipher engine will use the
L</COLUMN> and L</ROWID> methods to access that row content. The L</NEXT>
method will be used to advance to the next row.
=head3 EOF
This method must return false if the cursor currently points to a
valid row of data, or true otherwise. This method is called by the SQL
engine immediately after each L</FILTER> and L</NEXT> invocation.
=head3 NEXT
This method advances the cursor to the next row of a
result set initiated by L</FILTER>. If the cursor is already pointing at
the last row when this method is called, then the cursor no longer
points to valid data and a subsequent call to the L</EOF> method must
return true. If the cursor is successfully advanced to
another row of content, then subsequent calls to L</EOF> must return
false.
=head3 COLUMN
my $value = $cursor->COLUMN($idxCol);
The SQLcipher core invokes this method in order to find the value for the
N-th column of the current row. N is zero-based so the first column is
numbered 0.
=head3 ROWID
my $value = $cursor->ROWID;
Returns the I<rowid> of row that the cursor is currently pointing at.
=head1 SEE ALSO
L<SQLcipher::VirtualTable> is another module for virtual tables written
view all matches for this distribution
view release on metacpan or search on metacpan
dbdimp_tokenizer.inc view on Meta::CPAN
typedef struct perl_tokenizer {
sqlite3_tokenizer base;
SV *coderef; /* the perl tokenizer is a coderef that takes
a string and returns a cursor coderef */
} perl_tokenizer;
typedef struct perl_tokenizer_cursor {
sqlite3_tokenizer_cursor base;
SV *coderef; /* ref to the closure that returns terms */
char *pToken; /* storage for a copy of the last token */
int nTokenAllocated; /* space allocated to pToken buffer */
/* members below are only used if the input string is in utf8 */
const char *pInput; /* input we are tokenizing */
const char *lastByteOffset; /* offset into pInput */
int lastCharOffset; /* char offset corresponding to lastByteOffset */
} perl_tokenizer_cursor;
/*
** Create a new tokenizer instance.
** Will be called whenever a FTS3 table is created with
** CREATE .. USING fts3( ... , tokenize=perl qualified::function::name)
dbdimp_tokenizer.inc view on Meta::CPAN
/*
** Prepare to begin tokenizing a particular string. The input
** string to be tokenized is supposed to be pInput[0..nBytes-1] ..
** except that nBytes passed by fts3 is -1 (don't know why) !
** This is passed to the tokenizer instance, which then returns a
** closure implementing the cursor (so the cursor is again a coderef).
*/
static int perl_tokenizer_Open(
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
const char *pInput, int nBytes, /* Input buffer */
sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */
){
dTHX;
dSP;
dMY_CXT;
U32 flags;
SV *perl_string;
int n_retval;
perl_tokenizer *t = (perl_tokenizer *)pTokenizer;
/* allocate and initialize the cursor struct */
perl_tokenizer_cursor *c;
c = (perl_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));
memset(c, 0, sizeof(*c));
*ppCursor = &c->base;
/* flags for creating the Perl SV containing the input string */
flags = SVs_TEMP; /* will call sv_2mortal */
dbdimp_tokenizer.inc view on Meta::CPAN
XPUSHs(perl_string);
PUTBACK;
n_retval = call_sv(t->coderef, G_SCALAR);
SPAGAIN;
/* store the cursor coderef returned by the tokenizer */
if (n_retval != 1) {
warn("tokenizer returned %d arguments", n_retval);
}
c->coderef = newSVsv(POPs);
dbdimp_tokenizer.inc view on Meta::CPAN
LEAVE;
return SQLITE_OK;
}
/*
** Close a tokenization cursor previously opened by a call to
** perl_tokenizer_Open() above.
*/
static int perl_tokenizer_Close(sqlite3_tokenizer_cursor *pCursor){
perl_tokenizer_cursor *c = (perl_tokenizer_cursor *) pCursor;
dTHX;
sv_free(c->coderef);
if (c->pToken) sqlite3_free(c->pToken);
sqlite3_free(c);
return SQLITE_OK;
}
/*
** Extract the next token from a tokenization cursor. The cursor must
** have been opened by a prior call to perl_tokenizer_Open().
*/
static int perl_tokenizer_Next(
sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by perl_tokenizer_Open */
const char **ppToken, /* OUT: *ppToken is the token text */
int *pnBytes, /* OUT: Number of bytes in token */
int *piStartOffset, /* OUT: Starting offset of token */
int *piEndOffset, /* OUT: Ending offset of token */
int *piPosition /* OUT: Position integer of token */
){
perl_tokenizer_cursor *c = (perl_tokenizer_cursor *) pCursor;
int result;
int n_retval;
char *token;
char *byteOffset;
STRLEN n_a; /* this is required for older perls < 5.8.8 */
dbdimp_tokenizer.inc view on Meta::CPAN
dSP;
ENTER;
SAVETMPS;
/* call the cursor */
PUSHMARK(SP);
PUTBACK;
n_retval = call_sv(c->coderef, G_ARRAY);
SPAGAIN;
dbdimp_tokenizer.inc view on Meta::CPAN
result = SQLITE_DONE;
}
/* otherwise, get token details from the return list */
else {
if (n_retval != 5) {
warn("tokenizer cursor returned %d arguments", n_retval);
}
*piPosition = POPi;
*piEndOffset = POPi;
*piStartOffset = POPi;
*pnBytes = POPi;
dbdimp_tokenizer.inc view on Meta::CPAN
pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->pToken = pNew;
}
/* need to copy the token into the C cursor before perl frees that
memory */
memcpy(c->pToken, token, *pnBytes);
*ppToken = c->pToken;
result = SQLITE_OK;
view all matches for this distribution
view release on metacpan or search on metacpan
CODE:
D_imp_dbh(dbh);
if ( !DBIc_ACTIVE(imp_dbh) ) {
XSRETURN_YES;
}
/* Check for disconnect() being called whilst refs to cursors */
/* still exists. This possibly needs some more thought. */
if (DBIc_ACTIVE_KIDS(imp_dbh) && DBIc_WARN(imp_dbh) && !dirty) {
STRLEN lna;
char *plural = (DBIc_ACTIVE_KIDS(imp_dbh)==1) ? "" : "s";
warn("%s->disconnect invalidates %d active statement handle%s %s",
view all matches for this distribution
view release on metacpan or search on metacpan
lib/DBD/SQLite/GetInfo.pm view on Meta::CPAN
#
# Forward-only CA1: NEXT, BOOKMARK
#
# CA2: READ_ONLY_CONCURRENCY, LOCK_CONCURRENCY
144 => 0, # SQL_DYNAMIC_CURSOR_ATTRIBUTES1 - No dynamic cursor support
145 => 0, # SQL_DYNAMIC_CURSOR_ATTRIBUTES2 - No dynamic cursor support
146 => 1+8, # SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1
147 => 1+2, # SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2
150 => 0, # SQL_KEYSET_CURSOR_ATTRIBUTES1 - No keyset cursor support
151 => 0, # SQL_KEYSET_CURSOR_ATTRIBUTES2 - No keyset cursor support
167 => 466511, # SQL_STATIC_CURSOR_ATTRIBUTES1
168 => 1+2, # SQL_STATIC_CURSOR_ATTRIBUTES2
27 => 'Y', # SQL_EXPRESSIONS_IN_ORDERBY - ORDER BY allows expressions
8 => 63, # SQL_FETCH_DIRECTION - Cursors support next, first, last, prior, absolute, relative
lib/DBD/SQLite/GetInfo.pm view on Meta::CPAN
80 => 0, # SQL_POSITIONED_STATEMENTS - No support for positioned statements (WHERE CURRENT OF or SELECT FOR UPDATE)
79 => 31, # SQL_POS_OPERATIONS - Supports all SQLSetPos operations
21 => 'N', # SQL_PROCEDURES - No procedures
40 => '', # SQL_PROCEDURE_TERM - No procedures
93 => 4, # SQL_QUOTED_IDENTIFIER_CASE - Even quoted identifiers are case-insensitive
11 => 'N', # SQL_ROW_UPDATES - No fancy cursor update support
39 => '', # SQL_SCHEMA_TERM - No schemas
91 => 0, # SQL_SCHEMA_USAGE - No schemas
43 => 2, # SQL_SCROLL_CONCURRENCY - Updates/deletes on cursors lock the database
44 => 1+16, # SQL_SCROLL_OPTIONS - Only supports static & forward-only cursors
14 => '\\', # SQL_SEARCH_PATTERN_ESCAPE - Default escape character for LIKE is \
13 => \&sql_server_name, # SQL_SERVER_NAME - Just $dbh->{Name}
94 => '', # SQL_SPECIAL_CHARACTERS - Other drivers tend to stick to the ASCII/Latin-1 range, and SQLite uses all of
# the lower 7-bit punctuation for other things
view all matches for this distribution
view release on metacpan or search on metacpan
** Everything we need to know about an open database
*/
struct Btree {
BtOps *pOps; /* Function table */
Pager *pPager; /* The page cache */
BtCursor *pCursor; /* A list of all open cursors */
PageOne *page1; /* First page of the database */
u8 inTrans; /* True if a transaction is in progress */
u8 inCkpt; /* True if there is a checkpoint on the transaction */
u8 readOnly; /* True if the underlying file is readonly */
u8 needSwab; /* Need to byte-swapping */
};
typedef Btree Bt;
/*
** A cursor is a pointer to a particular entry in the BTree.
** The entry is identified by its MemPage and the index in
** MemPage.apCell[] of the entry.
*/
struct BtCursor {
BtCursorOps *pOps; /* Function table */
Btree *pBt; /* The Btree to which this cursor belongs */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
BtCursor *pShared; /* Loop of cursors with the same root page */
Pgno pgnoRoot; /* The root page of this tree */
MemPage *pPage; /* Page that contains the entry */
int idx; /* Index of the entry in pPage->apCell[] */
u8 wrFlag; /* True if writable */
u8 eSkip; /* Determines if next step operation is a no-op */
};
/*
** Legal values for BtCursor.eSkip.
*/
#define SKIP_NONE 0 /* Always step the cursor */
#define SKIP_NEXT 1 /* The next sqliteBtreeNext() is a no-op */
#define SKIP_PREV 2 /* The next sqliteBtreePrevious() is a no-op */
#define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */
/* Forward declarations */
*ppBtree = pBt;
return SQLITE_OK;
}
/*
** Close an open database and invalidate all cursors.
*/
static int fileBtreeClose(Btree *pBt){
while( pBt->pCursor ){
fileBtreeCloseCursor(pBt->pCursor);
}
pBt->page1 = 0;
return rc;
}
/*
** If there are no outstanding cursors and we are not in the middle
** of a transaction but there is a read lock on the database, then
** this routine unrefs the first page of the database file which
** has the effect of releasing the read lock.
**
** If there are any outstanding cursors, this routine is a no-op.
**
** If there is a transaction in progress, this routine is a no-op.
*/
static void unlockBtreeIfUnused(Btree *pBt){
if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){
/*
** Commit the transaction currently in progress.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
static int fileBtreeCommit(Btree *pBt){
int rc;
rc = pBt->readOnly ? SQLITE_OK : sqlitepager_commit(pBt->pPager);
pBt->inTrans = 0;
unlockBtreeIfUnused(pBt);
return rc;
}
/*
** Rollback the transaction in progress. All cursors will be
** invalided by this operation. Any attempt to use a cursor
** that was open at the beginning of this operation will result
** in an error.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
static int fileBtreeRollback(Btree *pBt){
int rc;
BtCursor *pCur;
if( pBt->inTrans==0 ) return SQLITE_OK;
/*
** Rollback the checkpoint to the current transaction. If there
** is no active checkpoint or transaction, this routine is a no-op.
**
** All cursors will be invalided by this operation. Any attempt
** to use a cursor that was open at the beginning of this operation
** will result in an error.
*/
static int fileBtreeRollbackCkpt(Btree *pBt){
int rc;
BtCursor *pCur;
pBt->inCkpt = 0;
return rc;
}
/*
** Create a new cursor for the BTree whose root is on the page
** iTable. The act of acquiring a cursor gets a read lock on
** the database file.
**
** If wrFlag==0, then the cursor can only be used for reading.
** If wrFlag==1, then the cursor can be used for reading or for
** writing if other conditions for writing are also met. These
** are the conditions that must be met in order for writing to
** be allowed:
**
** 1: The cursor must have been opened with wrFlag==1
**
** 2: No other cursors may be open with wrFlag==0 on the same table
**
** 3: The database must be writable (not on read-only media)
**
** 4: There must be an active transaction.
**
** Condition 2 warrants further discussion. If any cursor is opened
** on a table with wrFlag==0, that prevents all other cursors from
** writing to that table. This is a kind of "read-lock". When a cursor
** is opened with wrFlag==0 it is guaranteed that the table will not
** change as long as the cursor is open. This allows the cursor to
** do a sequential scan of the table without having to worry about
** entries being inserted or deleted during the scan. Cursors should
** be opened with wrFlag==0 only if this read-lock property is needed.
** That is to say, cursors should be opened with wrFlag==0 only if they
** intend to use the sqliteBtreeNext() system call. All other cursors
** should be opened with wrFlag==1 even if they never really intend
** to write.
**
** No checking is done to make sure that page iTable really is the
** root page of a b-tree. If it is not, then the cursor acquired
** will not work correctly.
*/
static
int fileBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
int rc;
}
}
pCur = sqliteMalloc( sizeof(*pCur) );
if( pCur==0 ){
rc = SQLITE_NOMEM;
goto create_cursor_exception;
}
pCur->pgnoRoot = (Pgno)iTable;
rc = sqlitepager_get(pBt->pPager, pCur->pgnoRoot, (void**)&pCur->pPage);
if( rc!=SQLITE_OK ){
goto create_cursor_exception;
}
rc = initPage(pBt, pCur->pPage, pCur->pgnoRoot, 0);
if( rc!=SQLITE_OK ){
goto create_cursor_exception;
}
pCur->pOps = &sqliteBtreeCursorOps;
pCur->pBt = pBt;
pCur->wrFlag = wrFlag;
pCur->idx = 0;
}
pBt->pCursor = pCur;
*ppCur = pCur;
return SQLITE_OK;
create_cursor_exception:
*ppCur = 0;
if( pCur ){
if( pCur->pPage ) sqlitepager_unref(pCur->pPage);
sqliteFree(pCur);
}
unlockBtreeIfUnused(pBt);
return rc;
}
/*
** Close a cursor. The read lock on the database file is released
** when the last cursor is closed.
*/
static int fileBtreeCloseCursor(BtCursor *pCur){
Btree *pBt = pCur->pBt;
if( pCur->pPrev ){
pCur->pPrev->pNext = pCur->pNext;
sqliteFree(pCur);
return SQLITE_OK;
}
/*
** Make a temporary cursor by filling in the fields of pTempCur.
** The temporary cursor is not on the cursor list for the Btree.
*/
static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
memcpy(pTempCur, pCur, sizeof(*pCur));
pTempCur->pNext = 0;
pTempCur->pPrev = 0;
sqlitepager_ref(pTempCur->pPage);
}
}
/*
** Delete a temporary cursor such as was made by the CreateTemporaryCursor()
** function above.
*/
static void releaseTempCursor(BtCursor *pCur){
if( pCur->pPage ){
sqlitepager_unref(pCur->pPage);
}
}
/*
** Set *pSize to the number of bytes of key in the entry the
** cursor currently points to. Always return SQLITE_OK.
** Failure is not possible. If the cursor is not currently
** pointing to an entry (which can happen, for example, if
** the database is empty) then *pSize is set to 0.
*/
static int fileBtreeKeySize(BtCursor *pCur, int *pSize){
Cell *pCell;
}
return SQLITE_OK;
}
/*
** Read payload information from the entry that the pCur cursor is
** pointing to. Begin reading the payload at "offset" and read
** a total of "amt" bytes. Put the result in zBuf.
**
** This routine does not make a distinction between key and data.
** It just reads bytes from the payload area.
}
return SQLITE_OK;
}
/*
** Read part of the key associated with cursor pCur. A maximum
** of "amt" bytes will be transfered into zBuf[]. The transfer
** begins at "offset". The number of bytes actually read is
** returned.
**
** Change: It used to be that the amount returned will be smaller
return amt;
}
/*
** Set *pSize to the number of bytes of data in the entry the
** cursor currently points to. Always return SQLITE_OK.
** Failure is not possible. If the cursor is not currently
** pointing to an entry (which can happen, for example, if
** the database is empty) then *pSize is set to 0.
*/
static int fileBtreeDataSize(BtCursor *pCur, int *pSize){
Cell *pCell;
}
return SQLITE_OK;
}
/*
** Read part of the data associated with cursor pCur. A maximum
** of "amt" bytes will be transfered into zBuf[]. The transfer
** begins at "offset". The number of bytes actually read is
** returned. The amount returned will be smaller than the
** amount requested if there are not enough bytes in the data
** to satisfy the request.
*pResult = c;
return SQLITE_OK;
}
/*
** Move the cursor down to a new child page. The newPgno argument is the
** page number of the child page in the byte order of the disk image.
*/
static int moveToChild(BtCursor *pCur, int newPgno){
int rc;
MemPage *pNewPage;
}
return SQLITE_OK;
}
/*
** Move the cursor up to the parent page.
**
** pCur->idx is set to the cell index that contains the pointer
** to the page we are coming from. If we are coming from the
** right-most child page then pCur->idx is set to one more than
** the largest cell index.
}
}
}
/*
** Move the cursor to the root page
*/
static int moveToRoot(BtCursor *pCur){
MemPage *pNew;
int rc;
Btree *pBt = pCur->pBt;
pCur->idx = 0;
return SQLITE_OK;
}
/*
** Move the cursor down to the left-most leaf entry beneath the
** entry to which it is currently pointing.
*/
static int moveToLeftmost(BtCursor *pCur){
Pgno pgno;
int rc;
}
return SQLITE_OK;
}
/*
** Move the cursor down to the right-most leaf entry beneath the
** page to which it is currently pointing. Notice the difference
** between moveToLeftmost() and moveToRightmost(). moveToLeftmost()
** finds the left-most entry beneath the *entry* whereas moveToRightmost()
** finds the right-most entry beneath the *page*.
*/
}
pCur->idx = pCur->pPage->nCell - 1;
return SQLITE_OK;
}
/* Move the cursor to the first entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
*/
static int fileBtreeFirst(BtCursor *pCur, int *pRes){
int rc;
if( pCur->pPage==0 ) return SQLITE_ABORT;
rc = moveToLeftmost(pCur);
pCur->eSkip = SKIP_NONE;
return rc;
}
/* Move the cursor to the last entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
*/
static int fileBtreeLast(BtCursor *pCur, int *pRes){
int rc;
if( pCur->pPage==0 ) return SQLITE_ABORT;
rc = moveToRightmost(pCur);
pCur->eSkip = SKIP_NONE;
return rc;
}
/* Move the cursor so that it points to an entry near pKey.
** Return a success code.
**
** If an exact match is not found, then the cursor is always
** left pointing at a leaf page which would hold the entry if it
** were present. The cursor might point to an entry that comes
** before or after the key.
**
** The result of comparing the key with the entry to which the
** cursor is left pointing is stored in pCur->iMatch. The same
** value is also written to *pRes if pRes!=NULL. The meaning of
** this value is as follows:
**
** *pRes<0 The cursor is left pointing at an entry that
** is smaller than pKey or if the table is empty
** and the cursor is therefore left point to nothing.
**
** *pRes==0 The cursor is left pointing at an entry that
** exactly matches pKey.
**
** *pRes>0 The cursor is left pointing at an entry that
** is larger than pKey.
*/
static
int fileBtreeMoveto(BtCursor *pCur, const void *pKey, int nKey, int *pRes){
int rc;
}
/* NOT REACHED */
}
/*
** Advance the cursor to the next entry in the database. If
** successful then set *pRes=0. If the cursor
** was already pointing to the last entry in the database before
** this routine was called, then set *pRes=1.
*/
static int fileBtreeNext(BtCursor *pCur, int *pRes){
int rc;
rc = moveToLeftmost(pCur);
return rc;
}
/*
** Step the cursor to the back to the previous entry in the database. If
** successful then set *pRes=0. If the cursor
** was already pointing to the first entry in the database before
** this routine was called, then set *pRes=1.
*/
static int fileBtreePrevious(BtCursor *pCur, int *pRes){
int rc;
int nDiv; /* Number of cells in apDiv[] */
int i, j, k; /* Loop counters */
int idx; /* Index of pPage in pParent->apCell[] */
int nxDiv; /* Next divider slot in pParent->apCell[] */
int rc; /* The return code */
int iCur; /* apCell[iCur] is the cell of the cursor */
MemPage *pOldCurPage; /* The cursor originally points to this page */
int subtotal; /* Subtotal of bytes in cells on one page */
MemPage *extraUnref = 0; /* A page that needs to be unref-ed */
MemPage *apOld[NB]; /* pPage and up to two siblings */
Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */
MemPage *apNew[NB+1]; /* pPage and up to NB siblings after balancing */
apOld[i]->idxParent = k;
nOld++;
}
/*
** Set iCur to be the index in apCell[] of the cell that the cursor
** is pointing to. We will need this later on in order to keep the
** cursor pointing at the same cell. If pCur points to a page that
** has no involvement with this rebalancing, then set iCur to a large
** number so that the iCur==j tests always fail in the main cell
** distribution loop below.
*/
if( pCur ){
}
return rc;
}
/*
** This routine checks all cursors that point to the same table
** as pCur points to. If any of those cursors were opened with
** wrFlag==0 then this routine returns SQLITE_LOCKED. If all
** cursors point to the same table were opened with wrFlag==1
** then this routine returns SQLITE_OK.
**
** In addition to checking for read-locks (where a read-lock
** means a cursor opened with wrFlag==0) this routine also moves
** all cursors other than pCur so that they are pointing to the
** first Cell on root page. This is necessary because an insert
** or delete might change the number of cells on a page or delete
** a page entirely and we do not want to leave any cursors
** pointing to non-existant pages or cells.
*/
static int checkReadLocks(BtCursor *pCur){
BtCursor *p;
assert( pCur->wrFlag );
return SQLITE_OK;
}
/*
** Insert a new record into the BTree. The key is given by (pKey,nKey)
** and the data is given by (pData,nData). The cursor is used only to
** define what database the record should be inserted into. The cursor
** is left pointing at the new record.
*/
static int fileBtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */
const void *pKey, int nKey, /* The key of the new record */
const void *pData, int nData /* The data of the new record */
){
Cell newCell;
int rc;
int szNew;
MemPage *pPage;
Btree *pBt = pCur->pBt;
if( pCur->pPage==0 ){
return SQLITE_ABORT; /* A rollback destroyed this cursor */
}
if( !pBt->inTrans || nKey+nData==0 ){
/* Must start a transaction before doing an insert */
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
pCur->eSkip = SKIP_INVALID;
return rc;
}
/*
** Delete the entry that the cursor is pointing to.
**
** The cursor is left pointing at either the next or the previous
** entry. If the cursor is left pointing to the next entry, then
** the pCur->eSkip flag is set to SKIP_NEXT which forces the next call to
** sqliteBtreeNext() to be a no-op. That way, you can always call
** sqliteBtreeNext() after a delete and the cursor will be left
** pointing to the first entry after the deleted entry. Similarly,
** pCur->eSkip is set to SKIP_PREV is the cursor is left pointing to
** the entry prior to the deleted entry so that a subsequent call to
** sqliteBtreePrevious() will always leave the cursor pointing at the
** entry immediately before the one that was deleted.
*/
static int fileBtreeDelete(BtCursor *pCur){
MemPage *pPage = pCur->pPage;
Cell *pCell;
Pgno pgnoChild;
Btree *pBt = pCur->pBt;
assert( pPage->isInit );
if( pCur->pPage==0 ){
return SQLITE_ABORT; /* A rollback destroyed this cursor */
}
if( !pBt->inTrans ){
/* Must start a transaction before doing a delete */
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
assert( !pBt->readOnly );
if( pCur->idx >= pPage->nCell ){
return SQLITE_ERROR; /* The cursor is not pointing to anything */
}
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Did not open this cursor for writing */
}
if( checkReadLocks(pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
rc = sqlitepager_write(pPage);
if( !pBt->inTrans ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( pCur->pgnoRoot==(Pgno)iTable ){
return SQLITE_LOCKED; /* Cannot drop a table that has a cursor */
}
}
rc = sqlitepager_get(pBt->pPager, (Pgno)iTable, (void**)&pPage);
if( rc ) return rc;
rc = fileBtreeClearTable(pBt, iTable);
#endif
#ifdef SQLITE_TEST
/*
** Fill aResult[] with information about the entry and page that the
** cursor is pointing to.
**
** aResult[0] = The page number
** aResult[1] = The entry number
** aResult[2] = Total number of entries on this page
** aResult[3] = Size of this entry
view all matches for this distribution
view release on metacpan or search on metacpan
print "ok\n";
$ss_dbh->{PrintError} = 0;
print "Doing a query (expecting 'Data truncated' error)... ";
my $cursor = $ss_dbh->prepare ('select ft_text,ft_sfname,filesize,title from test where title contains \'pippo\'');
if ($cursor) {
print "(execute) ... ";
$cursor->execute;
print "ok, now fetching (fetchrow): ";
my $text;
my @row;
my $eot;
my $data_truncated = 0;
while (@row = $cursor->fetchrow) {
$data_truncated++ if ($cursor->state =~ /01004/);
}
print "checking data truncated condition... ";
if ($data_truncated == 0) {
print "FAILED: did not detect 01004 [Data truncated] condition!\n";
exit 1;
print "Doing another query (this time you'll see the data)... ";
$ss_dbh->{ss_maxhitsinternalcolumns} = 64;
print "\n\t\$dbh->{ss_maxhitsinternalcolumns} set to " . $ss_dbh->{ss_maxhitsinternalcolumns} . "\n";
# this allows for max 64 matches, or it will be
# truncated still.
$cursor = $ss_dbh->prepare ('select ft_text,ft_sfname,filesize,title from test where title contains \'pippo\'');
if ($cursor) {
print "\t(execute) ... ";
$cursor->execute;
print "\tok, now fetching (fetchrow):\n***\n";
my $text;
my @row;
my $eot;
my $data_truncated = 0;
while (@row = $cursor->fetchrow) {
$data_truncated++ if ($DBI::state =~ /truncated/);
$cursor->blob_read (1, 0, 8192, \$text);
#or (print "+++ RB NOT OK:$DBI::errstr\n");
$text = $` if ($text =~ /\x00/);
#[32703mpippo.[32723m
$row[3] =~ s!\e\[32703m!\<M\>!g;
$row[3] =~ s!\e\[32723m!\</M\>!g;
else {
print "FAILED: Prepare failed ($DBI::errstr)\n";
exit 1;
}
$cursor->finish;
$ss_dbh->disconnect;
print "Exiting\nIf you are here, then most likely all tests were successful.\n";
exit 0;
# end.
view all matches for this distribution
view release on metacpan or search on metacpan
CODE:
D_imp_dbh(dbh);
if ( !DBIc_ACTIVE(imp_dbh) ) {
XSRETURN_YES;
}
/* Check for disconnect() being called whilst refs to cursors */
/* still exists. This needs some more thought. */
if (DBIc_ACTIVE_KIDS(imp_dbh) && DBIc_WARN(imp_dbh) && !dirty) {
warn("disconnect(%s) invalidates %d active cursor(s)",
SvPV(dbh,na), (int)DBIc_ACTIVE_KIDS(imp_dbh));
}
ST(0) = dbd_db_disconnect(dbh) ? &sv_yes : &sv_no;
view all matches for this distribution
view release on metacpan or search on metacpan
the appropriate value they represent rather than just a literal
string of the field name, ie. "update table set FIELD1 = FIELD2"
should now work properly instead of setting FIELD1 to "FIELD2" in
every record of "table".
0.17 Fri Mar 09, 2001
- Fixed bug where types not returned for cursor after update,
Fixed bug where table names not returned if space appeared after
"table_name"?
- Fixed bug in "makesdb.pl" -- was encrypting wrong argument.
0.18 Wed Mar 13, 2001
- Changed comparisens of literal data with "CHAR" fields to first
view all matches for this distribution
view release on metacpan or search on metacpan
lib/DBD/Teradata.pm view on Meta::CPAN
$iobj->[31] = $dbh;
$dbh->{tdat_uses_cli} = 1;
$dbh->{tdat_versnum} = $iobj->[40];
$dbh->{_iobj} = $iobj;
$dbh->{_stmts} = { };
$dbh->{_nextcursor} = 0;
$dbh->{_cursors} = { };
$dbh->{_debug} = $ENV{TDAT_DBD_DEBUG};
$dbh->{_utf8} = ($attr->{tdat_charset} eq 'UTF8');
$dbh->{Active} = 1;
$drh->{_connections}{($dsn . '_' . $dbh->{tdat_sessno})} = $dbh
unless $attr->{tdat_passthru};
lib/DBD/Teradata.pm view on Meta::CPAN
NUM_OF_PARAMS => 0,
}
);
}
my $rowid = undef;
$rowid = $dbh->{_cursors}{uc $1}{_rowid}
if ($stmt=~/\s+WHERE\s+CURRENT\s+OF\s+([^\s;]+)\s*;?\s*$/i);
my $sth = $iobj->io_prepare($dbh, \&_make_sth, $stmt, $rowid, $attribs, $compatible, $passthru);
return $sth || $dbh->DBI::set_err($iobj->io_get_error());
}
sub _make_sth {
my ($dbh, $args) = @_;
delete $args->{tdat_clone};
delete $args->{tdat_passthru};
$args->{CursorName} = 'CURS' . $dbh->{_nextcursor};
$dbh->{_nextcursor}++;
$args->{tdat_stmt_num} = 0;
$args->{tdat_sessno} = $dbh->{tdat_sessno};
$args->{tdat_compatible} = '999.0'
unless $args->{tdat_compatible};
$args->{tdat_no_bigint} = $dbh->{tdat_no_bigint}
lib/DBD/Teradata.pm view on Meta::CPAN
$sth->{$key} = $val
while (($key, $val) = each %$args);
$dbh->{_stmts}{$sth->{CursorName}} = $sth;
Scalar::Util::weaken($dbh->{_stmts}{$sth->{CursorName}})
if $DBD::Teradata::HAS_WEAKEN;
$dbh->{_cursors}{$sth->{CursorName}} = $sth,
$sth->{tdat_keepresp} = 1,
$sthp[16] = 1
if ($#$stmtinfo == 1) &&
($stmtinfo->[1]{ActivityType} eq 'Select') &&
($sth->{Statement}=~/\s+FOR\s+CURSOR\s*;?\s*$/i);
lib/DBD/Teradata.pm view on Meta::CPAN
}
sub disconnect {
my $dbh = shift;
my $i;
$dbh->{Active} = undef;
$dbh->{_stmts} = $dbh->{_cursors} = undef;
return 1
unless defined($dbh->{tdat_sessno}) &&
defined($dbh->{Name}) && defined($dbh->{Driver});
my $sessno = $dbh->{tdat_sessno};
my $host;
lib/DBD/Teradata.pm view on Meta::CPAN
my ($ptypes, $plens, $usephs) =
($sthp->[2], $sthp->[9], $sthp->[15]);
my ($sessno, $dbh, $partition) =
($sth->{tdat_sessno}, $sthp->[23], $iobj->[19]);
my $loading = (($partition == 5) || ($partition == 4));
my ($use_cursor, $cursnm, $cursth) = (0, '', undef);
if ($sth->{Statement}=~/\s+WHERE\s+CURRENT\s+OF\s+([^\s;]+)\s*;?$/i) {
$cursnm = uc $1;
$cursth = $dbh->{_cursors}{$cursnm};
return $sth->DBI::set_err(-1, 'Specified cursor not defined or not updatable.', 'S1000')
unless $cursth;
return $sth->DBI::set_err(-1, 'Specified cursor not positioned on a valid row.', 'S1000')
unless $cursth->{_p}[6];
$use_cursor = 1;
}
$iobj->[14] = 0,
$sth->{tdat_keepresp} = 1
if ($sth->{Statement}=~/\s+FOR\s+CURSOR\s*;?$/i);
my $rawmode = $sth->{tdat_raw_in};
lib/DBD/Teradata.pm view on Meta::CPAN
$iobj->[11] = 1
if ($partition == 1) && ($dbh->{tdat_mode} eq 'ANSI');
return $tuples
if $attrs->{_fetch_sub};
my $rowcnt = $iobj->io_execute($sth, $datainfo, $indicdata,
($use_cursor ? $cursth->{_p}[6] : undef));
$sthp->[13] = $rowcnt;
return $sth->DBI::set_err($iobj->io_get_error())
unless defined($rowcnt);
$sth->{Active} = ($sth->{NUM_OF_FIELDS} != 0);
undef $sthp->[6]
view all matches for this distribution
view release on metacpan or search on metacpan
2006-11-22 [r519] Chad Wagner <chad.wagner@gmail.com>
* Removed unused variables, clean up.
* Removed odbc_more_results feature, not supported.
* Removed odbc_cursor_type feature.
* Removed 09multi test suite
2006-11-22 [r518] Chad Wagner <chad.wagner@gmail.com>
* Removed Changes POD.
view all matches for this distribution
view release on metacpan or search on metacpan
lib/DBD/Unify.pm view on Meta::CPAN
$dbh->do ($statement)
This is implemented as a call to 'EXECUTE IMMEDIATE' with all the
limitations that this implies.
=item commit and rollback invalidates open cursors
DBD::Unify does warn when a commit or rollback is issued on a $dbh
with open cursors.
Possibly a commit/rollback/disconnect should also undef the $sth's.
(This should probably be done in the DBI-layer as other drivers will
have the same problems).
After a commit or rollback the cursors are all ->finish'ed, i.e. they
are closed and the DBI/DBD will warn if an attempt is made to fetch
from them.
A future version of DBD::Unify might re-prepare the statement.
view all matches for this distribution
view release on metacpan or search on metacpan
lib/DBD/XBase.pm view on Meta::CPAN
}
$sth->{'xbase_rows'} = ( $_[0] ? $_[0] : '0E0' );
}
# Execute the current statement, possibly binding parameters. For
# nonselect commands the actions needs to be done here, for select we
# just create the cursor and wait for fetchrows
sub execute {
my $sth = shift;
# the binds_order arrayref holds the conversion from the first
# occurence of the named parameter to its name;
lib/DBD/XBase.pm view on Meta::CPAN
# exactly what selectfieldscount means
if (not $sth->FETCH('NUM_OF_FIELDS')) {
$sth->STORE('NUM_OF_FIELDS', $parsed_sql->{'selectfieldscount'});
}
# this cursor will be needed, because both select and update and
# delete with where clause need to fetch the data first
my $cursor = $xbase->prepare_select(@{$parsed_sql->{'usedfields'}});
# select with order by clause will be done using "substatement"
if ($command eq 'select' and defined $parsed_sql->{'orderfields'}) {
my @orderfields = @{$parsed_sql->{'orderfields'}};
lib/DBD/XBase.pm view on Meta::CPAN
# sort them and store in xbase_lines
$sth->{'xbase_lines'} =
[ map { [ @{$_}[scalar(@orderfields) .. scalar(@$_) - 1 ] ] }
sort { &{$fn}($a, $b) } @$data ];
} elsif ($command eq 'select') {
$sth->{'xbase_cursor'} = $cursor;
} elsif ($command eq 'delete') {
if (not defined $wherefn) {
my $last = $xbase->last_record;
for (my $i = 0; $i <= $last; $i++) {
if (not (($xbase->get_record_nf($i, 0))[0])) {
lib/DBD/XBase.pm view on Meta::CPAN
$rows++;
}
}
} else {
my $values;
while (defined($values = $cursor->fetch_hashref)) {
next unless &{$wherefn}($xbase, $values,
$bind_values, 0);
$xbase->delete_record($cursor->last_fetched);
$rows = 0 unless defined $rows;
$rows++;
}
}
} elsif ($command eq 'update') {
my $values;
while (defined($values = $cursor->fetch_hashref)) {
next if defined $wherefn and not
&{$wherefn}($xbase, $values, $bind_values);
my %newval;
@newval{ @{$parsed_sql->{'updatefields'}} } =
&{$parsed_sql->{'updatefn'}}($xbase, $values,
$bind_values);
$xbase->update_record_hash($cursor->last_fetched, %newval);
$rows = 0 unless defined $rows;
$rows++;
}
} elsif ($command eq 'drop') {
# dropping the table is really easy
lib/DBD/XBase.pm view on Meta::CPAN
sub fetch {
my $sth = shift;
my $retarray;
if (defined $sth->{'xbase_lines'}) {
$retarray = shift @{$sth->{'xbase_lines'}};
} elsif (defined $sth->{'xbase_cursor'}) {
my $cursor = $sth->{'xbase_cursor'};
my $wherefn = $sth->{'xbase_parsed_sql'}{'wherefn'};
my $xbase = $cursor->table;
my $values;
while (defined($values = $cursor->fetch_hashref)) {
### use Data::Dumper; print Dumper $sth->{'xbase_bind_values'};
next if defined $wherefn and not
&{$wherefn}($xbase, $values,
$sth->{'xbase_bind_values'});
last;
view all matches for this distribution
view release on metacpan or search on metacpan
lib/DBD/XMLSimple.pm view on Meta::CPAN
{
my($class, $data, $attr, $flags) = @_;
$attr->{table} = $data;
$attr->{readonly} = 1;
$attr->{cursor} = 0;
my $rc = $class->SUPER::new($data, $attr, $flags);
$rc->{col_names} = $attr->{col_names};
$rc->{col_nums} = $attr->{col_nums};
lib/DBD/XMLSimple.pm view on Meta::CPAN
sub fetch_row($$)
{
my($self, $data) = @_;
if($self->{'cursor'} >= $data->{'rows'}) {
return;
}
$self->{'cursor'}++;
my @fields = map { $self->{'data'}->{$self->{'cursor'}}->{$_ } } @{$self->{'col_names'}};
$self->{'row'} = \@fields;
return $self->{'row'};
}
view all matches for this distribution
view release on metacpan or search on metacpan
CODE:
D_imp_dbh(dbh);
if ( !DBIc_ACTIVE(imp_dbh) ) {
XSRETURN_YES;
}
/* Check for disconnect() being called whilst refs to cursors */
/* still exists. This possibly needs some more thought. */
if (DBIc_ACTIVE_KIDS(imp_dbh) && DBIc_WARN(imp_dbh) && !PL_dirty) {
STRLEN lna;
char *plural = (DBIc_ACTIVE_KIDS(imp_dbh)==1) ? (char*)"" : (char*)"s";
warn("%s->disconnect invalidates %d active statement handle%s %s",
view all matches for this distribution
view release on metacpan or search on metacpan
cci-src/src/cci/cas_cci.c view on Meta::CPAN
static void print_debug_msg (const char *format, ...);
static const char *dbg_tran_type_str (char type);
static const char *dbg_a_type_str (T_CCI_A_TYPE);
static const char *dbg_u_type_str (T_CCI_U_TYPE);
static const char *dbg_db_param_str (T_CCI_DB_PARAM db_param);
static const char *dbg_cursor_pos_str (T_CCI_CURSOR_POS cursor_pos);
static const char *dbg_sch_type_str (T_CCI_SCH_TYPE sch_type);
static const char *dbg_oid_cmd_str (T_CCI_OID_CMD oid_cmd);
static const char *dbg_isolation_str (T_CCI_TRAN_ISOLATION isol_level);
#endif
cci-src/src/cci/cas_cci.c view on Meta::CPAN
return error;
}
int
cci_cursor (int mapped_stmt_id, int offset, T_CCI_CURSOR_POS origin, T_CCI_ERROR * err_buf)
{
T_REQ_HANDLE *req_handle = NULL;
T_CON_HANDLE *con_handle = NULL;
int error = CCI_ER_NO_ERROR;
#ifdef CCI_FULL_DEBUG
CCI_DEBUG_PRINT (print_debug_msg
("(%d:%d)cci_cursor: %d %s", CON_ID (mapped_stmt_id), REQ_ID (mapped_stmt_id), offset,
dbg_cursor_pos_str (origin)));
#endif
reset_error_buffer (err_buf);
error = hm_get_statement (mapped_stmt_id, &con_handle, &req_handle);
if (error != CCI_ER_NO_ERROR)
cci-src/src/cci/cas_cci.c view on Meta::CPAN
set_error_buffer (err_buf, error, NULL);
return error;
}
reset_error_buffer (&(con_handle->err_buf));
error = qe_cursor (req_handle, con_handle, offset, (char) origin, &(con_handle->err_buf));
set_error_buffer (&(con_handle->err_buf), error, NULL);
get_last_error (con_handle, err_buf);
con_handle->used = false;
cci-src/src/cci/cas_cci.c view on Meta::CPAN
return CCI_ER_NO_ERROR;
}
int
cci_cursor_update (int mapped_stmt_id, int cursor_pos, int index, T_CCI_A_TYPE a_type, void *value,
T_CCI_ERROR * err_buf)
{
int error = CCI_ER_NO_ERROR;
T_REQ_HANDLE *req_handle = NULL;
T_CON_HANDLE *con_handle = NULL;
#ifdef CCI_DEBUG
CCI_DEBUG_PRINT (print_debug_msg
("(%d:%d)cci_cursor_update: %d %d %s %p", CON_ID (mapped_stmt_id), REQ_ID (mapped_stmt_id),
cursor_pos, index, dbg_a_type_str (a_type), value));
#endif
reset_error_buffer (err_buf);
error = hm_get_statement (mapped_stmt_id, &con_handle, &req_handle);
if (error != CCI_ER_NO_ERROR)
cci-src/src/cci/cas_cci.c view on Meta::CPAN
{
error = CCI_ER_NOT_UPDATABLE;
}
else
{
error = qe_cursor_update (req_handle, con_handle, cursor_pos, index, a_type, value, &(con_handle->err_buf));
}
set_error_buffer (&(con_handle->err_buf), error, NULL);
get_last_error (con_handle, err_buf);
con_handle->used = false;
cci-src/src/cci/cas_cci.c view on Meta::CPAN
case CCI_ER_COMMUNICATION:
return "Cannot communicate with server";
case CCI_ER_NO_MORE_DATA:
return "Invalid cursor position";
case CCI_ER_TRAN_TYPE:
return "Unknown transaction type";
case CCI_ER_STRING_PARAM:
cci-src/src/cci/cas_cci.c view on Meta::CPAN
case CCI_ER_REQ_HANDLE:
return "Cannot allocate request handle";
case CCI_ER_INVALID_CURSOR_POS:
return "Invalid cursor position";
case CCI_ER_OBJECT:
return "Invalid oid string";
case CCI_ER_CAS:
cci-src/src/cci/cas_cci.c view on Meta::CPAN
case CAS_ER_PARAM_NAME:
return "Invalid T_CCI_DB_PARAM value";
case CAS_ER_NO_MORE_DATA:
return "Invalid cursor position";
case CAS_ER_OBJECT:
return "Invalid oid";
case CAS_ER_OPEN_FILE:
cci-src/src/cci/cas_cci.c view on Meta::CPAN
case CAS_ER_MAX_CLIENT_EXCEEDED:
return "Proxy refused client connection. max clients exceeded";
case CAS_ER_INVALID_CURSOR_POS:
return "Invalid cursor position";
case CAS_ER_IS:
return "Not used";
default:
cci-src/src/cci/cas_cci.c view on Meta::CPAN
return "***";
}
}
static const char *
dbg_cursor_pos_str (T_CCI_CURSOR_POS cursor_pos)
{
switch (cursor_pos)
{
case CCI_CURSOR_FIRST:
return "CCI_CURSOR_FIRST";
case CCI_CURSOR_CURRENT:
return "CCI_CURSOR_CURRENT";
view all matches for this distribution
view release on metacpan or search on metacpan
PerlIO_printf(DBILOGFP, "\n--> dbd_st_finish\n");
}
/*
Cancel further fetches from this cursor.
We don't close the cursor till DESTROY.
The application may re execute it.
*/
if (imp_sth && imp_sth->result)
{
/*
view all matches for this distribution
view release on metacpan or search on metacpan
21/07/95:09:22 Added a field into imp_sth (currow) which keeps track of the
current row that's been fetched from the result struct. If I
can fix the return codes coming from fetchrow, it'll work!
21/07/95:10:30 Pondered bind variables in cursors. Since there isn't a bind
function in the API, I may have to frig the way that prepare/
execute works, ie, move the call to msqlQuery *after* it's
done some parsing for bind values......Hm.
21/07/95:10:35 Twiddled some bits in the fetchrow cycle.
view all matches for this distribution
view release on metacpan or search on metacpan
t/30insertfetch.t view on Meta::CPAN
or DbiError($dbh->err, $dbh->errstr);
#
# Now, try SELECT'ing the row out. This should fail.
#
Test($state or $cursor = $dbh->prepare("SELECT * FROM $table"
. " WHERE id = 1"))
or DbiError($dbh->err, $dbh->errstr);
Test($state or $cursor->execute)
or DbiError($cursor->err, $cursor->errstr);
my ($row, $errstr);
Test($state or (!defined($row = $cursor->fetchrow_arrayref) &&
(!defined($errstr = $cursor->errstr) ||
$cursor->errstr eq '')))
or DbiError($cursor->err, $cursor->errstr);
Test($state or $cursor->finish, "\$sth->finish failed")
or DbiError($cursor->err, $cursor->errstr);
Test($state or undef $cursor || 1);
#
# Finally drop the test table.
#
view all matches for this distribution