SQLite

Artifact [dddc11922f]
Login

Artifact dddc11922f583645318c9446d0d1920d0bc940cd:


/*
** 2004 November 21
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the DECLARE...CURSOR syntax
** of SQL and related processing.
**
** Do not confuse SQL cursors and B-tree cursors.  An SQL cursor (as
** implemented by this file) is a user-visible cursor that is created
** using the DECLARE...CURSOR command and deleted using CLOSE.  A
** B-tree cursor is an abstraction of the b-tree layer.  See the btree.c
** module for additional information.  There is also a VDBE-cursor that
** is used by the VDBE module.  Even though all these objects are called
** cursors, they are really very different things.  It is worth your while
** to fully understand the difference.
**
** @(#) $Id: cursor.c,v 1.1 2004/11/22 19:12:20 drh Exp $
*/
#ifndef SQLITE_OMIT_CURSOR
#include "sqliteInt.h"
#include "vdbeInt.h"

/*
** Delete a cursor object.
*/
void sqlite3CursorDelete(SqlCursor *p){
  if( p ){
    int i;
    sqlite3SelectDelete(p->pSelect);
    for(i=0; i<p->nPtr; i++){
      sqlite3VdbeMemRelease(&p->aPtr[i]);
    }
    sqliteFree(p->aPtr);
    sqliteFree(p);
  }
}

/*
** Look up a cursor by name.  Return NULL if not found.
*/
static SqlCursor *findCursor(sqlite3 *db, Token *pName){
  int i;
  SqlCursor *p;
  for(i=0; i<db->nSqlCursor; i++){
    p = db->apSqlCursor[i];
    if( p && sqlite3StrNICmp(p->zName, pName->z, pName->n)==0 ){
      return p;
    }
  }
  return 0;
}  

/*
** The parser calls this routine in order to create a new cursor.
** The arguments are the name of the new cursor and the SELECT statement
** that the new cursor will access.
*/
void sqlite3CursorCreate(Parse *pParse, Token *pName, Select *pSelect){
  SqlCursor *pNew;
  sqlite3 *db = pParse->db;
  int i;
  

  pNew = findCursor(db, pName);
  if( pNew ){
    sqlite3ErrorMsg(pParse, "another cursor named %T already exists", pName);
    goto end_create_cursor;
  }
  if( pSelect==0 ){
    /* This can only happen due to a prior malloc failure */
    goto end_create_cursor;
  }
  for(i=0; i<db->nSqlCursor; i++){
    if( db->apSqlCursor[i]==0 ) break;
  }
  if( i>=db->nSqlCursor ){
    db->apSqlCursor = sqliteRealloc(db->apSqlCursor, (i+1)*sizeof(pNew));
    db->nSqlCursor = i+1;
  }
  db->apSqlCursor[i] = pNew = sqliteMallocRaw( sizeof(*pNew) + pName->n + 1 );
  if( pNew==0 ) goto end_create_cursor;
  pNew->zName = (char*)&pNew[1];
  memcpy(pNew->zName, pName->z, pName->n);
  pNew->zName[pName->n] = 0;
  pNew->pSelect = sqlite3SelectDup(pSelect);
  pNew->nPtr = 0;
  pNew->aPtr = 0;
  pNew->idx = i;

end_create_cursor:
  sqlite3SelectDelete(pSelect);
}

/*
** The parser calls this routine in response to a CLOSE command.  Delete
** the cursor named in the argument.
*/
void sqlite3CursorClose(Parse *pParse, Token *pName){
  SqlCursor *p;
  sqlite3 *db = pParse->db;

  p = findCursor(db, pName);
  if( p==0 ){
    sqlite3ErrorMsg(pParse, "no such cursor: %T", pName);
    return;
  }
  assert( p->idx>=0 && p->idx<db->nSqlCursor );
  assert( db->apSqlCursor[p->idx]==p );
  db->apSqlCursor[p->idx] = 0;
  sqlite3CursorDelete(p);
}

/*
** The parser calls this routine when it sees a complete FETCH statement.
** This routine generates code to implement the FETCH.
**
** Information about the direction of the FETCH has already been inserted
** into the pParse structure by parser rules.  The arguments specify the
** name of the cursor from which we are fetching and the optional INTO
** clause.
*/
void sqlite3Fetch(Parse *pParse, Token *pName, IdList *pInto){
  SqlCursor *p;
  sqlite3 *db = pParse->db;
  Select *pCopy;
  Fetch sFetch;

  p = findCursor(db, pName);
  if( p==0 ){
    sqlite3ErrorMsg(pParse, "no such cursor: %T", pName);
    return;
  }
  sFetch.pCursor = p;
  pCopy = sqlite3SelectDup(p->pSelect);
  pCopy->pFetch = &sFetch;
  switch( pParse->fetchDir ){
    case TK_FIRST: {
      break;
    }
    case TK_LAST: {
      break;
    }
    case TK_NEXT: {
      break;
    }
    case TK_PRIOR: {
      break;
    }
    case TK_ABSOLUTE: {
      break;
    }
    default: {
      assert( pParse->fetchDir==TK_RELATIVE );
      break;
    }
  }
  sqlite3Select(pParse, pCopy, SRT_Callback, 0, 0, 0, 0, 0);
end_fetch:
  sqlite3IdListDelete(pInto);
}

#endif /* SQLITE_OMIT_CURSOR */