summaryrefslogtreecommitdiff
path: root/ext/sqlite/libsqlite/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/sqlite/libsqlite/src/select.c')
-rw-r--r--ext/sqlite/libsqlite/src/select.c254
1 files changed, 134 insertions, 120 deletions
diff --git a/ext/sqlite/libsqlite/src/select.c b/ext/sqlite/libsqlite/src/select.c
index c7525b3b6b..871f2e2c71 100644
--- a/ext/sqlite/libsqlite/src/select.c
+++ b/ext/sqlite/libsqlite/src/select.c
@@ -42,6 +42,9 @@ Select *sqliteSelectNew(
sqliteExprDelete(pHaving);
sqliteExprListDelete(pOrderBy);
}else{
+ if( pEList==0 ){
+ pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL,0,0,0), 0);
+ }
pNew->pEList = pEList;
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
@@ -335,9 +338,7 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
sqliteExprCode(pParse, pOrderBy->a[i].pExpr);
}
zSortOrder[pOrderBy->nExpr] = 0;
- sqliteVdbeAddOp(v, OP_SortMakeKey, pOrderBy->nExpr, 0);
- sqliteVdbeChangeP3(v, -1, zSortOrder, strlen(zSortOrder));
- sqliteFree(zSortOrder);
+ sqliteVdbeOp3(v, OP_SortMakeKey, pOrderBy->nExpr, 0, zSortOrder, P3_DYNAMIC);
sqliteVdbeAddOp(v, OP_SortPut, 0, 0);
}
@@ -360,8 +361,7 @@ void sqliteAddKeyType(Vdbe *v, ExprList *pEList){
zType[i] = sqliteExprType(pEList->a[i].pExpr)==SQLITE_SO_NUM ? 'n' : 't';
}
zType[i] = 0;
- sqliteVdbeChangeP3(v, -1, zType, nColumn);
- sqliteFree(zType);
+ sqliteVdbeChangeP3(v, -1, zType, P3_DYNAMIC);
}
/*
@@ -564,18 +564,19 @@ static void generateSortTail(
int eDest, /* Write the sorted results here */
int iParm /* Optional parameter associated with eDest */
){
- int end = sqliteVdbeMakeLabel(v);
+ int end1 = sqliteVdbeMakeLabel(v);
+ int end2 = sqliteVdbeMakeLabel(v);
int addr;
if( eDest==SRT_Sorter ) return;
sqliteVdbeAddOp(v, OP_Sort, 0, 0);
- addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end);
+ addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end1);
if( p->iOffset>=0 ){
sqliteVdbeAddOp(v, OP_MemIncr, p->iOffset, addr+4);
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
}
if( p->iLimit>=0 ){
- sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, end);
+ sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, end2);
}
switch( eDest ){
case SRT_Callback: {
@@ -601,7 +602,7 @@ static void generateSortTail(
case SRT_Mem: {
assert( nColumn==1 );
sqliteVdbeAddOp(v, OP_MemStore, iParm, 1);
- sqliteVdbeAddOp(v, OP_Goto, 0, end);
+ sqliteVdbeAddOp(v, OP_Goto, 0, end1);
break;
}
case SRT_Subroutine: {
@@ -619,7 +620,9 @@ static void generateSortTail(
}
}
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
- sqliteVdbeResolveLabel(v, end);
+ sqliteVdbeResolveLabel(v, end2);
+ sqliteVdbeAddOp(v, OP_Pop, 1, 0);
+ sqliteVdbeResolveLabel(v, end1);
sqliteVdbeAddOp(v, OP_SortReset, 0, 0);
}
@@ -645,9 +648,6 @@ static void generateColumnTypes(
){
Vdbe *v = pParse->pVdbe;
int i, j;
- if( pParse->useCallback && (pParse->db->flags & SQLITE_ReportTypes)==0 ){
- return;
- }
for(i=0; i<pEList->nExpr; i++){
Expr *p = pEList->a[i].pExpr;
char *zType = 0;
@@ -672,15 +672,14 @@ static void generateColumnTypes(
zType = "NUMERIC";
}
}
- sqliteVdbeAddOp(v, OP_ColumnName, i + pEList->nExpr, 0);
- sqliteVdbeChangeP3(v, -1, zType, P3_STATIC);
+ sqliteVdbeOp3(v, OP_ColumnName, i + pEList->nExpr, 0, zType, 0);
}
}
/*
** Generate code that will tell the VDBE the names of columns
** in the result set. This information is used to provide the
-** azCol[] vaolues in the callback.
+** azCol[] values in the callback.
*/
static void generateColumnNames(
Parse *pParse, /* Parser context */
@@ -689,21 +688,24 @@ static void generateColumnNames(
){
Vdbe *v = pParse->pVdbe;
int i, j;
+ sqlite *db = pParse->db;
+ int fullNames, shortNames;
+
+ assert( v!=0 );
if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
pParse->colNamesSet = 1;
+ fullNames = (db->flags & SQLITE_FullColNames)!=0;
+ shortNames = (db->flags & SQLITE_ShortColNames)!=0;
for(i=0; i<pEList->nExpr; i++){
Expr *p;
- char *zType = 0;
- int showFullNames;
+ int p2 = i==pEList->nExpr-1;
p = pEList->a[i].pExpr;
if( p==0 ) continue;
if( pEList->a[i].zName ){
char *zName = pEList->a[i].zName;
- sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
+ sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, 0);
continue;
}
- showFullNames = (pParse->db->flags & SQLITE_FullColNames)!=0;
if( p->op==TK_COLUMN && pTabList ){
Table *pTab;
char *zCol;
@@ -715,39 +717,31 @@ static void generateColumnNames(
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
zCol = "_ROWID_";
- zType = "INTEGER";
}else{
zCol = pTab->aCol[iCol].zName;
- zType = pTab->aCol[iCol].zType;
}
- if( p->span.z && p->span.z[0] && !showFullNames ){
- int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
+ if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
+ int addr = sqliteVdbeOp3(v,OP_ColumnName, i, p2, p->span.z, p->span.n);
sqliteVdbeCompressSpace(v, addr);
- }else if( pTabList->nSrc>1 || showFullNames ){
+ }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
char *zName = 0;
char *zTab;
zTab = pTabList->a[j].zAlias;
- if( showFullNames || zTab==0 ) zTab = pTab->zName;
+ if( fullNames || zTab==0 ) zTab = pTab->zName;
sqliteSetString(&zName, zTab, ".", zCol, 0);
- sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
- sqliteFree(zName);
+ sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, P3_DYNAMIC);
}else{
- sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, zCol, 0);
+ sqliteVdbeOp3(v, OP_ColumnName, i, p2, zCol, 0);
}
}else if( p->span.z && p->span.z[0] ){
- int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
+ int addr = sqliteVdbeOp3(v,OP_ColumnName, i, p2, p->span.z, p->span.n);
sqliteVdbeCompressSpace(v, addr);
}else{
char zName[30];
assert( p->op!=TK_COLUMN || pTabList==0 );
sprintf(zName, "column%d", i+1);
- sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
- sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
+ sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, 0);
}
}
}
@@ -777,8 +771,9 @@ static int fillInColumnList(Parse*, Select*);
*/
Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
Table *pTab;
- int i;
+ int i, j;
ExprList *pEList;
+ Column *aCol;
if( fillInColumnList(pParse, pSelect) ){
return 0;
@@ -791,17 +786,27 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
pEList = pSelect->pEList;
pTab->nCol = pEList->nExpr;
assert( pTab->nCol>0 );
- pTab->aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
+ pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
for(i=0; i<pTab->nCol; i++){
- Expr *p;
+ Expr *p, *pR;
if( pEList->a[i].zName ){
- pTab->aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
- }else if( (p=pEList->a[i].pExpr)->span.z && p->span.z[0] ){
+ aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
+ }else if( (p=pEList->a[i].pExpr)->op==TK_DOT
+ && (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){
+ int cnt;
+ sqliteSetNString(&aCol[i].zName, pR->token.z, pR->token.n, 0);
+ for(j=cnt=0; j<i; j++){
+ if( sqliteStrICmp(aCol[j].zName, aCol[i].zName)==0 ){
+ int n;
+ char zBuf[30];
+ sprintf(zBuf,"_%d",++cnt);
+ n = strlen(zBuf);
+ sqliteSetNString(&aCol[i].zName, pR->token.z, pR->token.n, zBuf, n,0);
+ j = -1;
+ }
+ }
+ }else if( p->span.z && p->span.z[0] ){
sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0);
- }else if( p->op==TK_DOT && p->pRight && p->pRight->token.z &&
- p->pRight->token.z[0] ){
- sqliteSetNString(&pTab->aCol[i].zName,
- p->pRight->token.z, p->pRight->token.n, 0);
}else{
char zBuf[30];
sprintf(zBuf, "column%d", i+1);
@@ -1262,7 +1267,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
** |
** `-----> SELECT b FROM t2
** |
-** `------> SELECT c FROM t1
+** `------> SELECT a FROM t1
**
** The arrows in the diagram above represent the Select.pPrior pointer.
** So if this routine is called with p equal to the t3 query, then
@@ -1485,14 +1490,6 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
" do not have the same number of result columns", selectOpName(p->op));
return 1;
}
-
- /* Issue a null callback if that is what the user wants.
- */
- if( eDest==SRT_Callback &&
- (pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0)
- ){
- sqliteVdbeAddOp(v, OP_NullCallback, p->pEList->nExpr, 0);
- }
return 0;
}
@@ -1512,25 +1509,29 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */
static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
if( pExpr==0 ) return;
- if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){
- Expr *pNew;
- assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
- assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
- pNew = pEList->a[pExpr->iColumn].pExpr;
- assert( pNew!=0 );
- pExpr->op = pNew->op;
- pExpr->dataType = pNew->dataType;
- assert( pExpr->pLeft==0 );
- pExpr->pLeft = sqliteExprDup(pNew->pLeft);
- assert( pExpr->pRight==0 );
- pExpr->pRight = sqliteExprDup(pNew->pRight);
- assert( pExpr->pList==0 );
- pExpr->pList = sqliteExprListDup(pNew->pList);
- pExpr->iTable = pNew->iTable;
- pExpr->iColumn = pNew->iColumn;
- pExpr->iAgg = pNew->iAgg;
- sqliteTokenCopy(&pExpr->token, &pNew->token);
- sqliteTokenCopy(&pExpr->span, &pNew->span);
+ if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
+ if( pExpr->iColumn<0 ){
+ pExpr->op = TK_NULL;
+ }else{
+ Expr *pNew;
+ assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
+ assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
+ pNew = pEList->a[pExpr->iColumn].pExpr;
+ assert( pNew!=0 );
+ pExpr->op = pNew->op;
+ pExpr->dataType = pNew->dataType;
+ assert( pExpr->pLeft==0 );
+ pExpr->pLeft = sqliteExprDup(pNew->pLeft);
+ assert( pExpr->pRight==0 );
+ pExpr->pRight = sqliteExprDup(pNew->pRight);
+ assert( pExpr->pList==0 );
+ pExpr->pList = sqliteExprListDup(pNew->pList);
+ pExpr->iTable = pNew->iTable;
+ pExpr->iColumn = pNew->iColumn;
+ pExpr->iAgg = pNew->iAgg;
+ sqliteTokenCopy(&pExpr->token, &pNew->token);
+ sqliteTokenCopy(&pExpr->span, &pNew->span);
+ }
}else{
substExpr(pExpr->pLeft, iTable, pEList);
substExpr(pExpr->pRight, iTable, pEList);
@@ -1835,18 +1836,23 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
Vdbe *v;
int seekOp;
int cont;
- ExprList eList;
+ ExprList *pEList, *pList, eList;
struct ExprList_item eListItem;
+ SrcList *pSrc;
+
/* Check to see if this query is a simple min() or max() query. Return
** zero if it is not.
*/
if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
- if( p->pSrc->nSrc!=1 ) return 0;
- if( p->pEList->nExpr!=1 ) return 0;
- pExpr = p->pEList->a[0].pExpr;
+ pSrc = p->pSrc;
+ if( pSrc->nSrc!=1 ) return 0;
+ pEList = p->pEList;
+ if( pEList->nExpr!=1 ) return 0;
+ pExpr = pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
- if( pExpr->pList==0 || pExpr->pList->nExpr!=1 ) return 0;
+ pList = pExpr->pList;
+ if( pList==0 || pList->nExpr!=1 ) return 0;
if( pExpr->token.n!=3 ) return 0;
if( sqliteStrNICmp(pExpr->token.z,"min",3)==0 ){
seekOp = OP_Rewind;
@@ -1855,10 +1861,10 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
}else{
return 0;
}
- pExpr = pExpr->pList->a[0].pExpr;
+ pExpr = pList->a[0].pExpr;
if( pExpr->op!=TK_COLUMN ) return 0;
iCol = pExpr->iColumn;
- pTab = p->pSrc->a[0].pTab;
+ pTab = pSrc->a[0].pTab;
/* If we get to here, it means the query is of the correct form.
** Check to make sure we have an index and make pIdx point to the
@@ -1886,24 +1892,30 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
generateColumnTypes(pParse, p->pSrc, p->pEList);
}
+ /* If the output is destined for a temporary table, open that table.
+ */
+ if( eDest==SRT_TempTable ){
+ sqliteVdbeAddOp(v, OP_OpenTemp, iParm, 0);
+ }
+
/* Generating code to find the min or the max. Basically all we have
** to do is find the first or the last entry in the chosen index. If
** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
** or last entry in the main table.
*/
sqliteCodeVerifySchema(pParse, pTab->iDb);
- base = p->pSrc->a[0].iCursor;
+ base = pSrc->a[0].iCursor;
computeLimitRegisters(pParse, p);
- sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
- sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
- sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
+ if( pSrc->a[0].pSelect==0 ){
+ sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
+ sqliteVdbeOp3(v, OP_OpenRead, base, pTab->tnum, pTab->zName, 0);
+ }
cont = sqliteVdbeMakeLabel(v);
if( pIdx==0 ){
sqliteVdbeAddOp(v, seekOp, base, 0);
}else{
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
- sqliteVdbeAddOp(v, OP_OpenRead, base+1, pIdx->tnum);
- sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
+ sqliteVdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum, pIdx->zName, P3_STATIC);
sqliteVdbeAddOp(v, seekOp, base+1, 0);
sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0);
sqliteVdbeAddOp(v, OP_Close, base+1, 0);
@@ -1916,6 +1928,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont);
sqliteVdbeResolveLabel(v, cont);
sqliteVdbeAddOp(v, OP_Close, base, 0);
+
return 1;
}
@@ -1935,7 +1948,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
**
** SRT_Union Store results as a key in a temporary table iParm
**
-** SRT_Except Remove results form the temporary table iParm.
+** SRT_Except Remove results from the temporary table iParm.
**
** SRT_Table Store results in temporary table iParm
**
@@ -2156,14 +2169,6 @@ int sqliteSelect(
generateColumnNames(pParse, pTabList, pEList);
}
- /* Check for the special case of a min() or max() function by itself
- ** in the result set.
- */
- if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
- rc = 0;
- goto select_end;
- }
-
/* Generate code for all sub-queries in the FROM clause
*/
for(i=0; i<pTabList->nSrc; i++){
@@ -2193,6 +2198,14 @@ int sqliteSelect(
isDistinct = p->isDistinct;
}
+ /* Check for the special case of a min() or max() function by itself
+ ** in the result set.
+ */
+ if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
+ rc = 0;
+ goto select_end;
+ }
+
/* Check to see if this is a subquery that can be "flattened" into its parent.
** If flattening is a possiblity, do so and return immediately.
*/
@@ -2262,8 +2275,7 @@ int sqliteSelect(
for(i=0; i<pParse->nAgg; i++){
FuncDef *pFunc;
if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){
- sqliteVdbeAddOp(v, OP_AggInit, 0, i);
- sqliteVdbeChangeP3(v, -1, (char*)pFunc, P3_POINTER);
+ sqliteVdbeOp3(v, OP_AggInit, 0, i, (char*)pFunc, P3_POINTER);
}
}
if( pGroupBy==0 ){
@@ -2308,6 +2320,7 @@ int sqliteSelect(
** processing.
*/
else{
+ AggExpr *pAgg;
if( pGroupBy ){
int lbl1;
for(i=0; i<pGroupBy->nExpr; i++){
@@ -2317,29 +2330,27 @@ int sqliteSelect(
if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pGroupBy);
lbl1 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1);
- for(i=0; i<pParse->nAgg; i++){
- if( pParse->aAgg[i].isAgg ) continue;
- sqliteExprCode(pParse, pParse->aAgg[i].pExpr);
+ for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
+ if( pAgg->isAgg ) continue;
+ sqliteExprCode(pParse, pAgg->pExpr);
sqliteVdbeAddOp(v, OP_AggSet, 0, i);
}
sqliteVdbeResolveLabel(v, lbl1);
}
- for(i=0; i<pParse->nAgg; i++){
+ for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
Expr *pE;
- int j;
- if( !pParse->aAgg[i].isAgg ) continue;
- pE = pParse->aAgg[i].pExpr;
+ int nExpr;
+ FuncDef *pDef;
+ if( !pAgg->isAgg ) continue;
+ assert( pAgg->pFunc!=0 );
+ assert( pAgg->pFunc->xStep!=0 );
+ pDef = pAgg->pFunc;
+ pE = pAgg->pExpr;
+ assert( pE!=0 );
assert( pE->op==TK_AGG_FUNCTION );
- if( pE->pList ){
- for(j=0; j<pE->pList->nExpr; j++){
- sqliteExprCode(pParse, pE->pList->a[j].pExpr);
- }
- }
+ nExpr = sqliteExprCodeExprList(pParse, pE->pList, pDef->includeTypes);
sqliteVdbeAddOp(v, OP_Integer, i, 0);
- sqliteVdbeAddOp(v, OP_AggFunc, 0, pE->pList ? pE->pList->nExpr : 0);
- assert( pParse->aAgg[i].pFunc!=0 );
- assert( pParse->aAgg[i].pFunc->xStep!=0 );
- sqliteVdbeChangeP3(v, -1, (char*)pParse->aAgg[i].pFunc, P3_POINTER);
+ sqliteVdbeOp3(v, OP_AggFunc, 0, nExpr, (char*)pDef, P3_POINTER);
}
}
@@ -2375,13 +2386,16 @@ int sqliteSelect(
generateSortTail(p, v, pEList->nExpr, eDest, iParm);
}
-
- /* Issue a null callback if that is what the user wants.
+ /* If this was a subquery, we have now converted the subquery into a
+ ** temporary table. So delete the subquery structure from the parent
+ ** to prevent this subquery from being evaluated again and to force the
+ ** the use of the temporary table.
*/
- if( eDest==SRT_Callback &&
- (pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0)
- ){
- sqliteVdbeAddOp(v, OP_NullCallback, pEList->nExpr, 0);
+ if( pParent ){
+ assert( pParent->pSrc->nSrc>parentTab );
+ assert( pParent->pSrc->a[parentTab].pSelect==p );
+ sqliteSelectDelete(p);
+ pParent->pSrc->a[parentTab].pSelect = 0;
}
/* The SELECT was successfully coded. Set the return code to 0